From da9e427512b9ec8e073f903e73b5ea52995332c5 Mon Sep 17 00:00:00 2001 From: Paul Liverman Date: Wed, 6 May 2015 23:13:50 -0700 Subject: [PATCH] lots of rewrite --- old/main.lua | 157 +++++++++++++++++++ {src => old}/wheel.lua | 0 src/lib/inspect.lua | 327 ++++++++++++++++++++++++++++++++++++++++ src/lib/middleclass.lua | 182 ++++++++++++++++++++++ src/main.lua | 138 +++-------------- src/ships/Node.lua | 34 ++++- src/ships/Resources.lua | 50 ++++++ src/ships/Ship.lua | 84 +++++++++++ src/ships/bsg.lua | 86 +++++++---- src/ships/viper.lua | 47 +++--- 10 files changed, 916 insertions(+), 189 deletions(-) create mode 100644 old/main.lua rename {src => old}/wheel.lua (100%) create mode 100644 src/lib/inspect.lua create mode 100644 src/lib/middleclass.lua create mode 100644 src/ships/Resources.lua create mode 100644 src/ships/Ship.lua diff --git a/old/main.lua b/old/main.lua new file mode 100644 index 0000000..e199e5d --- /dev/null +++ b/old/main.lua @@ -0,0 +1,157 @@ +local bsg = require "ships.bsg" +local viper = require "ships.viper" + +local lg = love.graphics + +local images = {} +local ships = {} + +local hx, hy = lg.getWidth() / 2, lg.getHeight() / 2 + +local scale = 8 + +local selected + +function love.load() + lg.setDefaultFilter("linear", "nearest", 1) + images.bsg = lg.newImage('img/bsg.png') + images.viper = lg.newImage('img/viper.png') + lg.setPointSize(10) + lg.setPointStyle("rough") + + ships[1] = bsg() + for i=1,8 do + local v = viper() + table.insert(ships, v) + ships[1]:dock(v, i) + end +end + +local timer = 0 +function love.update(dt) + timer = timer + dt + if timer >= 33 then + timer = timer - 33 + end +end + +local function drawClock(x, y, r) + local time = math.floor(33 - timer) + if time == 0 then time = 33 end + + local maxTime = 33 + + local segments = 33 + local segmentRadius = math.pi*2 / segments + local dividerRadius = segmentRadius / 2 + --local time = 33 + + lg.setColor(255, 102, 0) + for i=1,time do + lg.arc("fill", x, y, r, (i-1)*segmentRadius - math.pi/2, i*segmentRadius - dividerRadius - math.pi/2) + end + lg.setColor(0, 0, 0) + lg.circle("fill", x, y, r/1.15) + + -- this looks cool and all, but it is the same function as the outer ring + -- instead, use this internal space for displaying things like fuel and water and supplies + --[[ + segments = 12 + segmentRadius = math.pi*2 / segments + dividerRadius = segmentRadius / segments * 2 + time = math.floor(time/maxTime * segments) --33 -> 12 percentage = time/maxTime..multiply this by 12 + + lg.setColor(255, 102, 0) + for i=1,time do + lg.arc("fill", x, y, r/1.5, (i-1)*segmentRadius - math.pi/2, i*segmentRadius - dividerRadius - math.pi/2) + end + lg.setColor(0, 0, 0) + lg.circle("fill", x, y, r/2) + --]] + + --tmp, really each color-dependent section should do this itself! + lg.setColor(255, 255, 255) +end + +local drawWheel = require "wheel"; + +function love.draw() + lg.translate(hx, hy) + + for i=1,#ships do + lg.draw(images[ships[i].img], ships[i].x * scale, ships[i].y * scale, ships[i].rotation, scale, scale, ships[i].ox, ships[i].oy) + end + + if selected then + lg.setColor(220, 180, 0) + lg.point(selected.x * scale, selected.y * scale) + lg.setColor(255, 255, 255) + end + + --drawClock(-355, -145, 120) + drawWheel(-355, -145, 120, timer) +end + +function love.keypressed(key, unicode) + if key == "escape" then + love.event.quit() + end +end + +local function pointInRadius(x, y, cx, cy, r) + cx = cx * scale + hx + cy = cy * scale + hy + local dx = x - cx + local dy = y - cy + return r * scale >= math.sqrt(dx * dx + dy * dy) +end + +local function pointInAABB(x, y, cx, cy, s, r) + -- THIS IS HORRIBLY WRONG, FIX IT LATER + --[[ + var x=((objects[i].x-objects[renderId].x)*Math.cos(rot)-(objects[i].y-objects[renderId].y)*Math.sin(rot))*scaleFactor; + var y=((objects[i].x-objects[renderId].x)*Math.sin(rot)+(objects[i].y-objects[renderId].y)*Math.cos(rot))*scaleFactor; + ]] + local nx = (x - cx) * math.cos(r) - (y - cy) * math.sin(r) + local ny = (x - cx) * math.sin(r) + (y - cy) * math.cos(r) + x = nx + y = ny + cx = cx * scale + hx + cy = cy * scale + hy + return x >= cx - s.w * scale / 2 and x <= cx + s.w * scale / 2 and y >= cy - s.h * scale / 2 and y <= cy + s.h * scale / 2 +end + +function love.mousepressed(x, y, button) + if button == "l" then + if selected then + -- find out where this actually is, now the ship selected is ordered to move to this point + selected.ship:moveTo(x * scale + hx, y * scale + hy) + else + for i=1,#ships do + if ships[i].selection.r then + if pointInRadius(x, y, ships[i].x, ships[i].y, ships[i].selection.r) then + -- selected + -- NOW CHECK IF HAS NODES AND IF WE ARE SELECTING A SHIP ON A NODE! + selected = {} + selected.ship = ships[i] + selected.x = ships[i].x + selected.y = ships[i].y + end + else + if pointInAABB(x, y, ships[i].x, ships[i].y, ships[i].selection, ships[i].rotation) then + -- we are selecting it! + -- NOW CHECK IF HAS NODES AND IF WE ARE SELECTING A SHIP ON A NODE! + selected = {} + selected.ship = ships[i] + selected.x = ships[i].x + selected.y = ships[i].y + end + end + end + end + elseif button == "wd" then + scale = scale * 1.1 + elseif button == "wu" then + scale = scale * 0.9 + end +end diff --git a/src/wheel.lua b/old/wheel.lua similarity index 100% rename from src/wheel.lua rename to old/wheel.lua diff --git a/src/lib/inspect.lua b/src/lib/inspect.lua new file mode 100644 index 0000000..08a44fa --- /dev/null +++ b/src/lib/inspect.lua @@ -0,0 +1,327 @@ +local inspect ={ + _VERSION = 'inspect.lua 3.0.0', + _URL = 'http://github.com/kikito/inspect.lua', + _DESCRIPTION = 'human-readable representations of tables', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2013 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) +inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) + +-- Apostrophizes the string if it has quotes, but not aphostrophes +-- Otherwise, it returns a regular quoted string +local function smartQuote(str) + if str:match('"') and not str:match("'") then + return "'" .. str .. "'" + end + return '"' .. str:gsub('"', '\\"') .. '"' +end + +local controlCharsTranslation = { + ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", + ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" +} + +local function escape(str) + local result = str:gsub("\\", "\\\\"):gsub("(%c)", controlCharsTranslation) + return result +end + +local function isIdentifier(str) + return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) +end + +local function isSequenceKey(k, length) + return type(k) == 'number' + and 1 <= k + and k <= length + and math.floor(k) == k +end + +local defaultTypeOrders = { + ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, + ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 +} + +local function sortKeys(a, b) + local ta, tb = type(a), type(b) + + -- strings and numbers are sorted numerically/alphabetically + if ta == tb and (ta == 'string' or ta == 'number') then return a < b end + + local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] + -- Two default types are compared according to the defaultTypeOrders table + if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] + elseif dta then return true -- default types before custom ones + elseif dtb then return false -- custom types after default ones + end + + -- custom types are sorted out alphabetically + return ta < tb +end + +local function getNonSequentialKeys(t) + local keys, length = {}, #t + for k,_ in pairs(t) do + if not isSequenceKey(k, length) then table.insert(keys, k) end + end + table.sort(keys, sortKeys) + return keys +end + +local function getToStringResultSafely(t, mt) + local __tostring = type(mt) == 'table' and rawget(mt, '__tostring') + local str, ok + if type(__tostring) == 'function' then + ok, str = pcall(__tostring, t) + str = ok and str or 'error: ' .. tostring(str) + end + if type(str) == 'string' and #str > 0 then return str end +end + +local maxIdsMetaTable = { + __index = function(self, typeName) + rawset(self, typeName, 0) + return 0 + end +} + +local idsMetaTable = { + __index = function (self, typeName) + local col = setmetatable({}, {__mode = "kv"}) + rawset(self, typeName, col) + return col + end +} + +local function countTableAppearances(t, tableAppearances) + tableAppearances = tableAppearances or setmetatable({}, {__mode = "k"}) + + if type(t) == 'table' then + if not tableAppearances[t] then + tableAppearances[t] = 1 + for k,v in pairs(t) do + countTableAppearances(k, tableAppearances) + countTableAppearances(v, tableAppearances) + end + countTableAppearances(getmetatable(t), tableAppearances) + else + tableAppearances[t] = tableAppearances[t] + 1 + end + end + + return tableAppearances +end + +local copySequence = function(s) + local copy, len = {}, #s + for i=1, len do copy[i] = s[i] end + return copy, len +end + +local function makePath(path, ...) + local keys = {...} + local newPath, len = copySequence(path) + for i=1, #keys do + newPath[len + i] = keys[i] + end + return newPath +end + +local function processRecursive(process, item, path) + if item == nil then return nil end + + local processed = process(item, path) + if type(processed) == 'table' then + local processedCopy = {} + local processedKey + + for k,v in pairs(processed) do + processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY)) + if processedKey ~= nil then + processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey)) + end + end + + local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE)) + setmetatable(processedCopy, mt) + processed = processedCopy + end + return processed +end + + +------------------------------------------------------------------- + +local Inspector = {} +local Inspector_mt = {__index = Inspector} + +function Inspector:puts(...) + local args = {...} + local buffer = self.buffer + local len = #buffer + for i=1, #args do + len = len + 1 + buffer[len] = tostring(args[i]) + end +end + +function Inspector:down(f) + self.level = self.level + 1 + f() + self.level = self.level - 1 +end + +function Inspector:tabify() + self:puts(self.newline, string.rep(self.indent, self.level)) +end + +function Inspector:alreadyVisited(v) + return self.ids[type(v)][v] ~= nil +end + +function Inspector:getId(v) + local tv = type(v) + local id = self.ids[tv][v] + if not id then + id = self.maxIds[tv] + 1 + self.maxIds[tv] = id + self.ids[tv][v] = id + end + return id +end + +function Inspector:putKey(k) + if isIdentifier(k) then return self:puts(k) end + self:puts("[") + self:putValue(k) + self:puts("]") +end + +function Inspector:putTable(t) + if t == inspect.KEY or t == inspect.METATABLE then + self:puts(tostring(t)) + elseif self:alreadyVisited(t) then + self:puts('') + elseif self.level >= self.depth then + self:puts('{...}') + else + if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end + + local nonSequentialKeys = getNonSequentialKeys(t) + local length = #t + local mt = getmetatable(t) + local toStringResult = getToStringResultSafely(t, mt) + + self:puts('{') + self:down(function() + if toStringResult then + self:puts(' -- ', escape(toStringResult)) + if length >= 1 then self:tabify() end + end + + local count = 0 + for i=1, length do + if count > 0 then self:puts(',') end + self:puts(' ') + self:putValue(t[i]) + count = count + 1 + end + + for _,k in ipairs(nonSequentialKeys) do + if count > 0 then self:puts(',') end + self:tabify() + self:putKey(k) + self:puts(' = ') + self:putValue(t[k]) + count = count + 1 + end + + if mt then + if count > 0 then self:puts(',') end + self:tabify() + self:puts(' = ') + self:putValue(mt) + end + end) + + if #nonSequentialKeys > 0 or mt then -- result is multi-lined. Justify closing } + self:tabify() + elseif length > 0 then -- array tables have one extra space before closing } + self:puts(' ') + end + + self:puts('}') + end +end + +function Inspector:putValue(v) + local tv = type(v) + + if tv == 'string' then + self:puts(smartQuote(escape(v))) + elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then + self:puts(tostring(v)) + elseif tv == 'table' then + self:putTable(v) + else + self:puts('<',tv,' ',self:getId(v),'>') + end +end + +------------------------------------------------------------------- + +function inspect.inspect(root, options) + options = options or {} + + local depth = options.depth or math.huge + local newline = options.newline or '\n' + local indent = options.indent or ' ' + local process = options.process + + if process then + root = processRecursive(process, root, {}) + end + + local inspector = setmetatable({ + depth = depth, + buffer = {}, + level = 0, + ids = setmetatable({}, idsMetaTable), + maxIds = setmetatable({}, maxIdsMetaTable), + newline = newline, + indent = indent, + tableAppearances = countTableAppearances(root) + }, Inspector_mt) + + inspector:putValue(root) + + return table.concat(inspector.buffer) +end + +setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) + +return inspect diff --git a/src/lib/middleclass.lua b/src/lib/middleclass.lua new file mode 100644 index 0000000..57d3644 --- /dev/null +++ b/src/lib/middleclass.lua @@ -0,0 +1,182 @@ +local middleclass = { + _VERSION = 'middleclass v3.0.1', + _DESCRIPTION = 'Object Orientation for Lua', + _URL = 'https://github.com/kikito/middleclass', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2011 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +local function _setClassDictionariesMetatables(aClass) + local dict = aClass.__instanceDict + dict.__index = dict + + local super = aClass.super + if super then + local superStatic = super.static + setmetatable(dict, super.__instanceDict) + setmetatable(aClass.static, { __index = function(_,k) return dict[k] or superStatic[k] end }) + else + setmetatable(aClass.static, { __index = function(_,k) return dict[k] end }) + end +end + +local function _setClassMetatable(aClass) + setmetatable(aClass, { + __tostring = function() return "class " .. aClass.name end, + __index = aClass.static, + __newindex = aClass.__instanceDict, + __call = function(self, ...) return self:new(...) end + }) +end + +local function _createClass(name, super) + local aClass = { name = name, super = super, static = {}, __mixins = {}, __instanceDict={} } + aClass.subclasses = setmetatable({}, {__mode = "k"}) + + _setClassDictionariesMetatables(aClass) + _setClassMetatable(aClass) + + return aClass +end + +local function _createLookupMetamethod(aClass, name) + return function(...) + local method = aClass.super[name] + assert( type(method)=='function', tostring(aClass) .. " doesn't implement metamethod '" .. name .. "'" ) + return method(...) + end +end + +local function _setClassMetamethods(aClass) + for _,m in ipairs(aClass.__metamethods) do + aClass[m]= _createLookupMetamethod(aClass, m) + end +end + +local function _setDefaultInitializeMethod(aClass, super) + aClass.initialize = function(instance, ...) + return super.initialize(instance, ...) + end +end + +local function _includeMixin(aClass, mixin) + assert(type(mixin)=='table', "mixin must be a table") + for name,method in pairs(mixin) do + if name ~= "included" and name ~= "static" then aClass[name] = method end + end + if mixin.static then + for name,method in pairs(mixin.static) do + aClass.static[name] = method + end + end + if type(mixin.included)=="function" then mixin:included(aClass) end + aClass.__mixins[mixin] = true +end + +local Object = _createClass("Object", nil) + +Object.static.__metamethods = { '__add', '__call', '__concat', '__div', '__ipairs', '__le', + '__len', '__lt', '__mod', '__mul', '__pairs', '__pow', '__sub', + '__tostring', '__unm'} + +function Object.static:allocate() + assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'") + return setmetatable({ class = self }, self.__instanceDict) +end + +function Object.static:new(...) + local instance = self:allocate() + instance:initialize(...) + return instance +end + +function Object.static:subclass(name) + assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'") + assert(type(name) == "string", "You must provide a name(string) for your class") + + local subclass = _createClass(name, self) + _setClassMetamethods(subclass) + _setDefaultInitializeMethod(subclass, self) + self.subclasses[subclass] = true + self:subclassed(subclass) + + return subclass +end + +function Object.static:subclassed(other) end + +function Object.static:isSubclassOf(other) + return type(other) == 'table' and + type(self) == 'table' and + type(self.super) == 'table' and + ( self.super == other or + type(self.super.isSubclassOf) == 'function' and + self.super:isSubclassOf(other) + ) +end + +function Object.static:include( ... ) + assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'") + for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end + return self +end + +function Object.static:includes(mixin) + return type(mixin) == 'table' and + type(self) == 'table' and + type(self.__mixins) == 'table' and + ( self.__mixins[mixin] or + type(self.super) == 'table' and + type(self.super.includes) == 'function' and + self.super:includes(mixin) + ) +end + +function Object:initialize() end + +function Object:__tostring() return "instance of " .. tostring(self.class) end + +function Object:isInstanceOf(aClass) + return type(self) == 'table' and + type(self.class) == 'table' and + type(aClass) == 'table' and + ( aClass == self.class or + type(aClass.isSubclassOf) == 'function' and + self.class:isSubclassOf(aClass) + ) +end + + + +function middleclass.class(name, super, ...) + super = super or Object + return super:subclass(name, ...) +end + +middleclass.Object = Object + +setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end }) + +return middleclass diff --git a/src/main.lua b/src/main.lua index e199e5d..b1749fe 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,95 +1,49 @@ -local bsg = require "ships.bsg" -local viper = require "ships.viper" +--tmp +local inspect = require "lib.inspect" local lg = love.graphics -local images = {} -local ships = {} - local hx, hy = lg.getWidth() / 2, lg.getHeight() / 2 - local scale = 8 +local images = {} +local fleet = {} + +local bsg = require "ships.bsg" +local viper = require "ships.viper" + +--tmp local selected function love.load() lg.setDefaultFilter("linear", "nearest", 1) images.bsg = lg.newImage('img/bsg.png') images.viper = lg.newImage('img/viper.png') + --tmp lg.setPointSize(10) lg.setPointStyle("rough") - ships[1] = bsg() + fleet[1] = bsg() for i=1,8 do local v = viper() - table.insert(ships, v) - ships[1]:dock(v, i) + table.insert(fleet, v) + fleet[1]:dock(v, i) end end -local timer = 0 -function love.update(dt) - timer = timer + dt - if timer >= 33 then - timer = timer - 33 - end -end - -local function drawClock(x, y, r) - local time = math.floor(33 - timer) - if time == 0 then time = 33 end - - local maxTime = 33 - - local segments = 33 - local segmentRadius = math.pi*2 / segments - local dividerRadius = segmentRadius / 2 - --local time = 33 - - lg.setColor(255, 102, 0) - for i=1,time do - lg.arc("fill", x, y, r, (i-1)*segmentRadius - math.pi/2, i*segmentRadius - dividerRadius - math.pi/2) - end - lg.setColor(0, 0, 0) - lg.circle("fill", x, y, r/1.15) - - -- this looks cool and all, but it is the same function as the outer ring - -- instead, use this internal space for displaying things like fuel and water and supplies - --[[ - segments = 12 - segmentRadius = math.pi*2 / segments - dividerRadius = segmentRadius / segments * 2 - time = math.floor(time/maxTime * segments) --33 -> 12 percentage = time/maxTime..multiply this by 12 - - lg.setColor(255, 102, 0) - for i=1,time do - lg.arc("fill", x, y, r/1.5, (i-1)*segmentRadius - math.pi/2, i*segmentRadius - dividerRadius - math.pi/2) - end - lg.setColor(0, 0, 0) - lg.circle("fill", x, y, r/2) - --]] - - --tmp, really each color-dependent section should do this itself! - lg.setColor(255, 255, 255) -end - -local drawWheel = require "wheel"; - function love.draw() lg.translate(hx, hy) - for i=1,#ships do - lg.draw(images[ships[i].img], ships[i].x * scale, ships[i].y * scale, ships[i].rotation, scale, scale, ships[i].ox, ships[i].oy) + lg.setColor(255, 255, 255) + for i=1,#fleet do + lg.draw(images[fleet[i].img], fleet[i].x * scale, fleet[i].y * scale, fleet[i].rotation, scale, scale, fleet[i].ox, fleet[i].oy) end + --tmp if selected then lg.setColor(220, 180, 0) lg.point(selected.x * scale, selected.y * scale) - lg.setColor(255, 255, 255) end - - --drawClock(-355, -145, 120) - drawWheel(-355, -145, 120, timer) end function love.keypressed(key, unicode) @@ -97,61 +51,3 @@ function love.keypressed(key, unicode) love.event.quit() end end - -local function pointInRadius(x, y, cx, cy, r) - cx = cx * scale + hx - cy = cy * scale + hy - local dx = x - cx - local dy = y - cy - return r * scale >= math.sqrt(dx * dx + dy * dy) -end - -local function pointInAABB(x, y, cx, cy, s, r) - -- THIS IS HORRIBLY WRONG, FIX IT LATER - --[[ - var x=((objects[i].x-objects[renderId].x)*Math.cos(rot)-(objects[i].y-objects[renderId].y)*Math.sin(rot))*scaleFactor; - var y=((objects[i].x-objects[renderId].x)*Math.sin(rot)+(objects[i].y-objects[renderId].y)*Math.cos(rot))*scaleFactor; - ]] - local nx = (x - cx) * math.cos(r) - (y - cy) * math.sin(r) - local ny = (x - cx) * math.sin(r) + (y - cy) * math.cos(r) - x = nx - y = ny - cx = cx * scale + hx - cy = cy * scale + hy - return x >= cx - s.w * scale / 2 and x <= cx + s.w * scale / 2 and y >= cy - s.h * scale / 2 and y <= cy + s.h * scale / 2 -end - -function love.mousepressed(x, y, button) - if button == "l" then - if selected then - -- find out where this actually is, now the ship selected is ordered to move to this point - selected.ship:moveTo(x * scale + hx, y * scale + hy) - else - for i=1,#ships do - if ships[i].selection.r then - if pointInRadius(x, y, ships[i].x, ships[i].y, ships[i].selection.r) then - -- selected - -- NOW CHECK IF HAS NODES AND IF WE ARE SELECTING A SHIP ON A NODE! - selected = {} - selected.ship = ships[i] - selected.x = ships[i].x - selected.y = ships[i].y - end - else - if pointInAABB(x, y, ships[i].x, ships[i].y, ships[i].selection, ships[i].rotation) then - -- we are selecting it! - -- NOW CHECK IF HAS NODES AND IF WE ARE SELECTING A SHIP ON A NODE! - selected = {} - selected.ship = ships[i] - selected.x = ships[i].x - selected.y = ships[i].y - end - end - end - end - elseif button == "wd" then - scale = scale * 1.1 - elseif button == "wu" then - scale = scale * 0.9 - end -end diff --git a/src/ships/Node.lua b/src/ships/Node.lua index 9fda710..0619a3e 100644 --- a/src/ships/Node.lua +++ b/src/ships/Node.lua @@ -1,11 +1,35 @@ -return function(x, y, rotation) - local self = {} +local class = require "lib.middleclass" +local Node = class('Node') + +function Node:initialize(x, y, rotation) self.x = x or 0 self.y = y or 0 self.rotation = rotation or 0 - self.docked = false - - return self + self.dockedShip = false end + +--TODO docking needs to check distance between ships and only allow +-- docking when close enough +function Node:dock(Ship) + if self.dockedShip or Ship.dockedTo then + error("Attempted to dock to Node with something already docked to it!") + else + self.dockedShip = Ship + Ship.dockedTo = self + + Ship:setPosition(self.x, self.y, self.rotation) + end +end + +function Node:undock() + if not self.dockedShip then + error("Attempted to undock a ship from a Node with no docked ship.") + else + self.dockedShip.dockedTo = false + self.dockedShip = false + end +end + +return Node diff --git a/src/ships/Resources.lua b/src/ships/Resources.lua new file mode 100644 index 0000000..057a080 --- /dev/null +++ b/src/ships/Resources.lua @@ -0,0 +1,50 @@ +local class = require "lib.middleclass" + +local Resources = class('Resources') + +function Resources:initialize() + self.ammo = 0 + self.fuel = 0 + self.supplies = 0 + self.water = 0 + self.food = 0 + self.metal = 0 + self.ore = 0 + self.crew = 0 + + self.missiles = 0 + self.nukes = 0 + + self.maxAmmo = 0 + self.maxFuel = 0 + self.maxSupplies = 0 + self.maxWater = 0 + self.maxFood = 0 + self.maxMetal = 0 + self.maxOre = 0 + self.maxCrew = 0 + + self.ammoUse = 0 + self.fuelUseIdle = 0 + self.fuelUseMoving = 0 + self.fuelUseJump = 0 + self.suppliesUse = 0 + self.waterUse = 0 + self.foodUse = 0 + self.metalUse = 0 + self.oreUse = 0 + self.crewUse = 0 +end + +function Resources:maxEverything() + self.ammo = self.maxAmmo + self.fuel = self.maxFuel + self.supplies = self.maxSupplies + self.water = self.maxWater + self.food = self.maxFood + self.metal = self.maxMetal + self.ore = self.maxOre + self.crew = self.maxCrew +end + +return Resources diff --git a/src/ships/Ship.lua b/src/ships/Ship.lua new file mode 100644 index 0000000..9bd8326 --- /dev/null +++ b/src/ships/Ship.lua @@ -0,0 +1,84 @@ +local class = require "lib.middleclass" + +local Resources = require "ships.Resources" + +local Ship = class('Ship') + +function Ship:initialize(x, y, rotation) + self.img = "" + --offsets + self.ox = 0 + self.oy = 0 + + self.x = x or 0 + self.y = y or 0 + self.destination = { + x = x or 0, + y = y or 0 + } + self.rotation = rotation or 0 + + self.selection = {} + + self.node = {} + + self.dockedTo = false + + self.Resources = Resources() +end + +function Ship:dock(targetShip, nodeIndex) + if self.node[nodeIndex] then + self.node[nodeIndex]:dock(targetShip) + else + error("Ship attempted to dock to non-existent Node.") + end +end + +function Ship:undock(nodeIndex) + if self.node[nodeIndex] then + self.node[nodeIndex]:undock() + else + --find which node "nodeIndex" is docked to + for i=1,#self.node do + if self.node[i].dockedShip == nodeIndex then + self.node[i]:undock() + return + end + end + error("Ship attempted to undock from non-existent Node.") + end +end + +function Ship:dockTo(targetShip, nodeIndex) + if targetShip.node[nodeIndex] then + targetShip.node[nodeIndex]:dock(self) + else + error("Ship attempted to dock to non-existent Node.") + end +end + +function Ship:undockFromParent() + self.dockedTo:undock(self) +end + +function Ship:setPosition(x, y, rotation) + self.x = x or self.x + self.y = y or self.y + self.rotation = rotation or self.rotation +end + +function Ship:moveTo(x, y) + if self.dockedTo then + self:undockFromParent() + end + self.destination.x = x + self.destination.y = y +end + +function Ship:update(dt) + --check our speed, see how far along the "line" we can go, go there + -- if reached destination ... WELL SHIT DEST NEEDS TO BE ABLE TO KNOW IF IS SHIP OR WHATEVER +end + +return Ship diff --git a/src/ships/bsg.lua b/src/ships/bsg.lua index fbf8327..e3e85ca 100644 --- a/src/ships/bsg.lua +++ b/src/ships/bsg.lua @@ -1,18 +1,21 @@ -local Node = require "ships.Node" +math.randomseed(os.time()) +math.random() math.random() +local class = require "lib.middleclass" + +local Ship = require "ships.Ship" +local Node = require "ships.Node" local ninety = 90 * math.pi / 180 -return function(x, y, rotation) - local self = {} +local BSG = class('BSG', Ship) +function BSG:initialize(x, y, rotation) + Ship.initialize(self, x, y, rotation) self.img = "bsg" + --offsets self.ox = 31.5 self.oy = 67 - self.x = x or 0 - self.y = y or 0 - self.rotation = rotation or 0 - --[[ self.selection = { w = 54, @@ -34,33 +37,50 @@ return function(x, y, rotation) Node(-23, 16.5, -ninety) } - self.dock = function(self, ship, node) - if self.node[node].docked or ship.isDocked then return false end + self.Resources.maxAmmo = 1000000 + self.Resources.maxFuel = 1300000 + self.Resources.maxSupplies = 40000 + --what the fuck are jp's ? + -- http://www.traditionaloven.com/culinary-arts/cooking/shortening/convert-japanese-cup-measure-of-shortening-to-fluid-ounce-floz-shortening.html + -- From show "10 mil JPs water lost, almost 60%" + self.Resources.maxWater = 16000000 + self.Resources.maxFood = 51000 + self.Resources.maxMetal = 80000 + --self.Resources.maxOre = 0 + self.Resources.maxCrew = 5100 - ship.x = self.node[node].x - ship.y = self.node[node].y - ship.rotation = self.node[node].rotation + self.Resources.ammo = math.random(100, 1300) + self.Resources.fuel = math.random(496000, 512000) + self.Resources.supplies = math.random(18000,21000) + self.Resources.water = math.random(14186500, 14989900) + self.Resources.food = math.random(34700, 39200) + self.Resources.metal = math.random(19200,21600) + --self.Resources.ore = 0 + self.Resources.crew = math.random(2870, 2960) - self.node[node].docked = ship - ship.isDocked = true - ship.dockedTo = self - ship.dockedNode = node - return true - end + self.Resources.missiles = math.random(5, 11) + --self.Resources.nukes = 0 - self.undock = function(self, node) - if not self.node[node].docked then return false end - - local ship = self.node[node].docked - ship.isDocked = false - ship.dockedTo = false - ship.dockedNode = false - self.node[node].docked = false - - return ship - end - - self.moveTo = function() end - - return self + --self.Resources.ammoUse = 0 + -- a year is 31,556,900 seconds + -- for 17 mil water to last ? + -- How about 1 water per second? + -- 195 days + self.Resources.fuelUseIdle = 0.04 + self.Resources.fuelUseMoving = 0.54 + self.Resources.fuelUseJump = 4000 + self.Resources.suppliesUse = 0.0013 + self.Resources.waterUse = 1 + -- 45k civs = 82+85+119+304 (590) tons food + -- 2.5 mil JPs water + -- these are per week numbers + -- 604800 seconds, 4.13 water per second + -- 1 ton = 2000 pounds + -- 1180000 pounds / sec = 1.95 food per second + self.Resources.foodUse = 0.099 + --self.Resources.metalUse = 0.002 -- this # assumes normal repairs, which I'm ignoring for this + --self.Resources.oreUse = 0 + --self.Resources.crewUse = 0 end + +return BSG diff --git a/src/ships/viper.lua b/src/ships/viper.lua index ce4b6a0..b1d2194 100644 --- a/src/ships/viper.lua +++ b/src/ships/viper.lua @@ -1,20 +1,16 @@ -return function(x, y, rotation) - local self = {} +local class = require "lib.middleclass" +local Ship = require "ships.Ship" + +local Viper = class('Viper', Ship) + +function Viper:initialize(x, y, rotation) + Ship.initialize(self, x, y, rotation) self.img = "viper" + --offsets self.ox = 4.5 self.oy = 7.5 - self.x = x or 0 - self.y = y or 0 - self.rotation = rotation or 0 - - self.destination = { - x = x or 0, - y = y or 0 - } - self.isMoving = false - --[[ self.selection = { w = 9, @@ -25,24 +21,15 @@ return function(x, y, rotation) r = 5 } - --self.node = false - self.isDocked = false - self.dockedTo = false - self.dockedNode = false + self.Resources.maxAmmo = 1800 --10 shots per second? 5s per barrel + self.Resources.maxFuel = 30000 --86400s = 1day, x = 1/2 day's thrust + self.Resources.maxCrew = 1 - self.moveTo = function(self, x, y) - if self.isDocked then - self.dockedTo:undock(self.dockedNode) - end - self.destination.x = x - self.destination.y = y - self.isMoving = true - end + self.Resources.ammo = math.random(0, 20) + self.Resources.fuel = math.random(120, 1500) - self.update = function(self, dt) - -- check if moving, check our speed, see how far along the "line" we can go, go there - -- if reached destination ... WELL SHIT DEST NEEDS TO BE ABLE TO KNOW IF IS SHIP OR WHATEVER - end - - return self + self.Resources.fuelUseIdle = 0.09 + self.Resources.fuelUseMoving = 0.76 end + +return Viper