· 5 years ago · Feb 02, 2020, 06:02 PM
1Compilation of all code for project ComponentBasedEngine
2
3/////////////////Entering file: DEBUG.lua/////////////////
4DEBUG = {}
5
6DEBUG.BOUNDING_BOXES = true
7--DEBUG.DATAPACK_LOAD = true
8--DEBUG.DATAPACK_CONTENTS = true
9--DEBUG.REG_APPLY = true
10--DEBUG.MASKS = true
11
12--DEBUG.EVENT_SUBS = true
13--DEBUG.EVENT_ATTACHES = true
14
15--DEBUG.OVERLOAD = true
16
17/////////////////Exiting file: DEBUG.lua/////////////////
18//--------------------------------------------------------------------------------------------------------
19/////////////////Entering file: EShapes.lua/////////////////
20local Enum = require "libs.Enum"
21
22return Enum [[ RECT CIRCLE POLY ]]
23
24/////////////////Exiting file: EShapes.lua/////////////////
25//--------------------------------------------------------------------------------------------------------
26/////////////////Entering file: IBoundingBox.lua/////////////////
27local Mixins = require "libs.Mixins"
28local Tables = require "libs.Tables"
29
30------------------------------ Private Methods ------------------------------
31local function getShape(self, s, a, b, c)
32 local p, f = love.physics
33
34 if s == self.RECT then f = p.newRectangleShape
35 elseif s == self.CIRCLE then f = p.newCircleShape
36 elseif s == self.POLY then f = p.newPolygonShape end
37 --TODO: add more shapes
38
39 --if b ~= nil, then offset at a/2, b/2 (rect),
40 --otherwise offset by a/2, a/2 (circle)
41 return f(a / 2, (b and b / 2 or a), a, b, c)
42-- return f(0, 0, a, b, c)
43end
44
45local function checkShapeDat(self, d)
46 local st = self.shapeType
47 d = d:lower()
48 if st == self.RECT then
49 return d == 'w' or d == 'h' or d == 'angle'
50 elseif st == self.CIRCLE then
51 return d == 'r'
52 end
53 return false
54end
55
56------------------------------ Constructor ------------------------------
57local IBoundingBox = Mixins("IBoundingBox")
58--- @function [parent=#behavior.IBoundingBox] init Construct a new BoundingBox.
59-- @param #object self An object of the class IBoundingBox was included on.
60-- @param #love.physics#World world The world to create the body in.
61-- @param #number x The x position of the bounding box (top left origin).
62-- @param #number y The y position of the bounding box (top left origin).
63-- @param #luaValue userData The value to assign to user data, if any.
64-- @param #love.physics#BodyType bodyType The type of the body; static, dynamic, or kinematic.
65-- @param #number bodyDensity Set the density of the body. If nil, uses Box2D's internal default density.
66-- @param #number bodyMass Set the mass of the body directly, ignoring size AND density. If nil, uses Box2D's internal mass computation.
67-- @param #number bodyFriction Set the friction of the body. If nil, uses Box2D's internal default friction.
68-- @param #number bodyRestitution Set the restitution of the body. If nil, uses Box2D's internal default restitution.
69-- @param #template.EShapes shapeType The shape of the body (Rect, Circle, Poly, Precise, etc...).
70-- @param #number a The first parameter to pass to the shape. Rect = w; Circle = r; Poly = vertices.
71-- @param #number b The second parameter to pass to the shape. Rect = h;
72-- @param #number c The third parameter to pass to the shape. Rect = angle;
73function IBoundingBox:init(world, x, y, userData,
74 bodyType, bodyDensity, bodyMass,
75 bodyFriction, bodyRestitution,
76 shapeType, a, b, c)
77 self.shapeType = shapeType
78 self.baseBodyDensity = bodyDensity
79 self.baseBodyFriction = bodyFriction
80 self.baseBodyRestitution = bodyRestitution
81 self.baseBodyMass = bodyMass
82 self.a, self.b, self.c = a, b, c
83 self.body = love.physics.newBody(world, x, y, bodyType)
84 self.shape = getShape(self, shapeType, a, b, c)
85 self.fixture = love.physics.newFixture(self.body, self.shape)
86
87 if bodyDensity then self.fixture:setDensity(bodyDensity) end
88 if bodyFriction then self.fixture:setFriction(bodyFriction) end
89 if bodyRestitution then self.fixture:setRestitution(bodyRestitution) end
90 if bodyMass then
91 local x, y, m, i = self.body:getMassData()
92 self.body:setMassData(x, y, bodyMass, i * bodyMass / m)
93 end
94 if userData then self.fixture:setUserData(userData) end
95
96 if DEBUG.MASKS then
97 local c = utils.toBin(self:getCategory(), 16, 4)
98 local m = utils.toBin(self:getMask(), 16, 4)
99 local str = "%s\tcategory:%s\tmask:%s"
100 local name = tostring(self)
101 if name:len() < 40 then
102 for i = 1, 40 - name:len() do
103 name = name .. ' '
104 end
105 end
106 print(str:format(name, c, m))
107 end
108 self:setCategory(self:getCategory())
109 self:setMask(self:getMask())
110end
111------------------------------ Constants ------------------------------
112IBoundingBox.RECT = 0
113IBoundingBox.CIRCLE = 1
114IBoundingBox.POLY = 2
115
116------------------------------ Categories (Endpoints) ------------------------------
117IBoundingBox.masks = {}
118local m = IBoundingBox.masks
119
120--Nibble 1
121m.BLOCK,
122m.FREE,
123m.FREE,
124m.FREE,
125
126--Nibble 2; Misc. Entities
127m.ITEM_DROP,
128m.FREE,
129m.FREE,
130m.FREE,
131
132--Nibble 3; Mobs
133m.HOSTILE_MOB,
134m.NEUTRAL_MOB,
135m.PASSIVE_MOB,
136m.PLAYER,
137
138--Nibble 4; Projectiles
139m.NPC_PRJ,
140m.PLAYER_PRJ,
141m.FREE,
142m.MP --TODO: Should an instance being created with m.MP emit an error or be allowed?
143
144--2^0 through 2^15 (16bits)
145 = 1, 2, 4, 8, 16, 32, 64, 128, 256, 516, 1024, 2048, 4096, 8192, 16384, 32768
146--[[
147Hierarchy:
148Solid ->
149 Block |E|
150
151 Entity ->
152 ItemDrop |E|
153 Projectile ->
154 PlayerPrj |E|
155 NpcPrj |E|
156 Mob ->
157 Player |E|
158 Npc ->
159 Hostile |E|
160 Neutral |E|
161 Passive |E|
162
163Powers:
164 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
165 1 2 4 8 10 20 40 80 100 200 400 800 1000 2000 4000 8000
166--]]
167
168------------------------------ Masks ------------------------------
169m.NPC = m.HOSTILE_MOB + m.NEUTRAL_MOB + m.PASSIVE_MOB
170m.MOB = m.NPC + m.PLAYER
171
172m.PRJ = m.NPC_PRJ + m.PLAYER_PRJ
173
174m.ENTITY = m.PRJ + m.MOB + m.ITEM_DROP
175
176m.SOLID = m.ENTITY + m.BLOCK
177
178------------------------------ Category/Mask Methods ------------------------------
179function IBoundingBox:setCategory(c)
180 local _, mask, group = self.fixture:getFilterData()
181 self.fixture:setFilterData(c, mask, group)
182end
183function IBoundingBox:addCategory(c) --TODO: check if category is already assigned.
184 local cat, mask, group = self.fixture:getFilterData()
185 self.fixture:setFilterData(cat + c, mask, group)
186end
187function IBoundingBox:removeCategory(c)
188 local cat, mask, group = self.fixture:getFilterData()
189 self.fixture:setFilterData(cat - c, mask, group)
190end
191
192function IBoundingBox:setMask(m)
193 local cat, _, group = self.fixture:getFilterData()
194 self.fixture:setFilterData(cat, m, group)
195end
196function IBoundingBox:addMask(m)
197 local cat, mask, group = self.fixture:getFilterData()
198 self.fixture:setFilterData(cat, mask + m, group)
199end
200function IBoundingBox:removeMask(m)
201 local cat, mask, group = self.fixture:getFilterData()
202 self.fixture:setFilterData(cat, mask - m, group)
203end
204
205------------------------------ Common Position Getters ------------------------------
206function IBoundingBox:getX() return self.body:getX() end
207function IBoundingBox:getY() return self.body:getY() end
208function IBoundingBox:getPos() return self.body:getX(), self.body:getY() end
209
210------------------------------ Common Position Setters ------------------------------
211function IBoundingBox:setX(x) self.body:setX(x) end
212function IBoundingBox:setY(y) self.body:setY(y) end
213function IBoundingBox:setPos(x, y) self:setX(x); self:setY(y) end
214
215------------------------------ Body Data Getters ------------------------------
216function IBoundingBox:isFixedRotation()
217 return self.body:isFixedRotation()
218end
219
220------------------------------ Body Data Setters ------------------------------
221function IBoundingBox:setFixedRotation(r)
222 local x, y, m, i = self.body:getMassData()
223 self.body:setFixedRotation(r)
224 local curM = self.body:getMass()
225 self.body:setMassData(x, y, m, i * m / curM)
226end
227
228------------------------------ Rectangle Data Getters ------------------------------
229function IBoundingBox:getW()
230 assert(checkShapeDat(self, 'w'), "getW can only be called on rectangular BoundingBoxes.")
231 return self.a
232end
233
234function IBoundingBox:getH()
235 assert(checkShapeDat(self, 'h'), "getH can only be called on rectangular BoundingBoxes.")
236 return self.b
237end
238
239function IBoundingBox:getAngle()
240 error "WIP"
241 assert(checkShapeDat(self, 'angle'), "getAngle can only be called on rectangular BoundingBoxes.")
242 return self.c
243end
244
245function IBoundingBox:getDims()
246 assert(checkShapeDat(self, 'w')
247 and checkShapeDat(self, 'h'), "getDims can only be called on rectangular BoundingBoxes.")
248-- and checkShapeDat(self.shapeType, 'angle'),"getDims can only be called on rectangular BoundingBoxes.")
249 return self.a, self.b --, self.c or 0
250end
251
252------------------------------ Rectangle Data Setters ------------------------------
253function IBoundingBox:setW(w)
254 assert(checkShapeDat(self, 'w'), "getW can only be called on rectangular BoundingBoxes.")
255 self.a = w; self:reshape()
256end
257
258function IBoundingBox:setH(h)
259 assert(checkShapeDat(self, 'h'), "getH can only be called on rectangular BoundingBoxes.")
260 self.b = h; self:reshape()
261end
262
263function IBoundingBox:setAngle(a)
264 assert(checkShapeDat(self, 'angle'), "getAngle can only be called on rectangular BoundingBoxes.")
265 self.c = a; self:reshape()
266end
267
268function IBoundingBox:setDims(w, h, a)
269 assert(checkShapeDat(self, 'w')
270 and checkShapeDat(self, 'h'), "getDims can only be called on rectangular BoundingBoxes.")
271 self.a, self.b, self.c = w, h, a; self:reshape()
272end
273
274------------------------------ Circle Data Getters ------------------------------
275function IBoundingBox:getRadius()
276 assert(checkShapeDat(self, 'r'), "getRadius can only be called on circular BoundingBoxes.")
277 return self.a
278end
279
280function IBoundingBox:getDiameter()
281 return self:getRadius() * 2
282end
283
284------------------------------ Circle Data Setters ------------------------------
285function IBoundingBox:setRadius(r)
286 assert(checkShapeDat(self, self, 'r'), "getRadius can only be called on circular BoundingBoxes.")
287 self.a = r; self:reshape()
288end
289
290------------------------------ Helper Methods ------------------------------
291function IBoundingBox:_reshape()
292 --TODO: Test; see if fixture requires refreshing too.
293 self.s = getShape(self, self.shapeType, self.a, self.b, self.c)
294end
295
296------------------------------ Object-common Methods ------------------------------
297function IBoundingBox:clone()
298 return IBoundingBox(self.x, self.y, self.body:getType(),
299 self.shapeType, self.a, self.b, self.c)
300end
301
302return IBoundingBox
303
304
305/////////////////Exiting file: IBoundingBox.lua/////////////////
306//--------------------------------------------------------------------------------------------------------
307/////////////////Entering file: IHealth.lua/////////////////
308local Mixins = require "libs.Mixins"
309--local Registry = require "istats.Registry"
310
311------------------------------ Upvalues ------------------------------
312
313------------------------------ Helper Methods ------------------------------
314
315------------------------------ Setup ------------------------------
316local IHealth = Mixins("IHealth")
317Mixins.onPostInit(IHealth, function(self)
318 self.maxHealth = self:getBaseMaxHealth()
319 ---If health was set by the instance, just bound it.
320 self.health = self.health and self:setHealth(self.health) or self.maxHealth
321end)
322
323function IHealth:setupHealth()
324 self.maxHealth = self:getBaseMaxHealth()
325 self.health = self.health and self:setHealth(self.health) or self.maxHealth
326end
327------------------------------ Heal / Hurt ------------------------------
328function IHealth:heal(n)
329 assert(n >= 0, "Cannot heal negatively.")
330 self.health = math.min(self.health + n, self.maxHealth)
331end
332function IHealth:hurt(n)
333 assert(n >= 0, "Cannot deal negative damage.")
334 if self.health == 0 then return end
335 self.health = math.max(self.health - n, 0)
336 if self.health == 0 then self:_onDeath() end
337end
338
339------------------------------ Restore / Kill ------------------------------
340function IHealth:restore() self.health = self.maxHealth end
341function IHealth:kill() self.health = 0; self:_onDeath() end
342
343------------------------------ Callback ------------------------------
344function IHealth:_onDeath() end
345
346------------------------------ Health Getters/Setters ------------------------------
347function IHealth:getHealth() return self.health end
348--function IHealth:rawSetHealth(n) health = n end
349function IHealth:setHealth(n)
350 self.health = math.max( math.min(n, self.maxHealth), 0 )
351 if self.health <= 0 then self:onDeath() end
352end
353
354------------------------------ MaxHealth Getters/Setters ------------------------------
355function IHealth:getMaxHealth() return self.maxHealth end
356--function IHealth:rawSetMaxHealth(n) maxHealth = n end
357function IHealth:setMaxHealth(n)
358 self.maxHealth = n; self.health = math.min(self.health, self.maxHealth)
359end
360
361------------------------------ BaseMaxHealth Getters/Setters ------------------------------
362function IHealth:getBaseMaxHealth() return self:getMaxHealth() end
363
364return IHealth
365
366
367
368
369/////////////////Exiting file: IHealth.lua/////////////////
370//--------------------------------------------------------------------------------------------------------
371/////////////////Entering file: IHittable.lua/////////////////
372local Mixins = require "libs.Mixins"
373local IBoundingBox = require "behavior.IBoundingBox"
374local IHealth = require "behavior.IHealth"
375
376local Scheduler = require "utils.Scheduler"
377local Game = require "core.Game"
378
379------------------------------ Upvalues ------------------------------
380
381------------------------------ Helper Methods ------------------------------
382
383------------------------------ Setup ------------------------------
384local IHittable = Mixins("IHittable")
385Mixins.onPostInit(IHittable, function(self)
386 assert(self:instanceof(IBoundingBox), "IMeleeAttack can only be applied on instances of IBoundingBox")
387 assert(self:instanceof(IHealth), "IMeleeAttack can only be applied on instances of IHealth")
388 self.invicCooldownMax = self.invicCooldownMax or 0.5
389-- self.invicCooldown = self.invicCooldown or 0
390 self.invic = false
391end)
392
393------------------------------ Main Methods ------------------------------
394function IHittable:getHit(attacker, dmg, knockback, effects)
395 if self:_onPreHit(attacker, dmg, knockback, effects) then
396 self:_onHit(attacker, dmg, knockback, effects)
397 return self:_onPostHit(attacker, dmg, knockback, effects)
398 end
399 return false
400end
401
402------------------------------ Callbacks ------------------------------
403function IHittable:_onPreHit(attacker, dmg, knockback, effects) return not self.invic end
404function IHittable:_onHit(attacker, dmg, knockback, effects)
405 self.invic = true
406 Scheduler:callAfter(self.invicCooldownMax, function() self.invic = false end)
407 self:hurt(20)
408 Scheduler:callFor(0.5, function()
409 self.body:applyForce(300, -5)
410 end)
411 if DEBUG.LOG_COMBAT then
412 print(self:getName() .. " got attacked by " .. attacker:getName())
413 end
414end
415function IHittable:_onPostHit(attacker, dmg, knockback, effects) return true end
416function IHittable:_onCancelledHit(attacker, dmg, knockback, effects) return false end
417
418return IHittable
419
420--[[
421 TODO: rename "getHit"
422getHit: Public interface for getting attacked (TODO: rename)
423
424onPreHit: Mainly used to cancel the hit. If it returns false, the latter are ignored.
425 Default: Cancels the hit if invincible, continues otherwise.
426onHit: The main effect/application of the hit.
427 Take dmg, knockback, effects, set invincibility, etc..
428 Default: Sets invincibility flag (and frames/cooldown),
429 Takes dmg, knockback, and applies effects (respects armor).
430onPostHit: Mainly used to customize the value returned by the public API.
431 (not called if the hit is cancelled)
432 Default: Returns true.
433
434onCancelledHit: Mainly used to customize the value returned by the public API.
435 (called only if onPreHit returned false)
436 Default: Returns false (default onPreHit only cancels if is invincible)
437
438Terminology:
439attack -> melee attack
440shoot -> ranged attacked
441throw -> projectile toss (similar to above)
442
443hit -> general; melee or ranged
444
445onX -> passed as callback
446? prefix for evsys event callbacks ?
447verb -> do action (e.g. attack)
448getVerb -> be object of action (e.g. getHit)
449--]]
450
451
452
453/////////////////Exiting file: IHittable.lua/////////////////
454//--------------------------------------------------------------------------------------------------------
455/////////////////Entering file: IMeleeAttack.lua/////////////////
456local Mixins = require "libs.Mixins"
457local IBoundingBox = require "behavior.IBoundingBox"
458local IHittable = require "behavior.IHittable"
459local WeaponDef = require "template.WeaponDef"
460
461local Mob = require "template.Mob"
462
463local Scheduler = require "utils.Scheduler"
464local Game = require "core.Game"
465
466------------------------------ Upvalues ------------------------------
467local onCollision, onHit, onAttackDone
468
469------------------------------ Helper Methods ------------------------------
470local function lerp(t, a, b)
471 return a * (1 - t) + b * t
472end
473
474local function lerpArea(t, a, b)
475 local x, y, w, h;
476 x = lerp(t, a[1], b[1])
477 y = lerp(t, a[2], b[2])
478 w = lerp(t, a[3], b[3])
479 h = lerp(t, a[4], b[4])
480 return {x, y, w, h}
481end
482
483--TODO: refactor into the abstraction layer for Box2D.
484local function box2dWrapper(a, b, ...)
485 local args, func, self = {...}
486 if type(a) == 'table' then
487 self, func = a, b
488 return function(fixt) func(self, fixt, unpack(args)) end
489 elseif type(a) == 'function' then
490 func = a; table.insert(args, 1, b)
491 return function(fixt) func(fixt, unpack(args)) end
492 else error "box2DWrapper must be called with (self, f, args) or (f, args)." end
493end
494
495------------------------------ Setup ------------------------------
496local IMeleeAttack = Mixins("IMeleeAttack")
497Mixins.onPostInit(IMeleeAttack, function(self)
498 assert(self:instanceof(IBoundingBox), "IMeleeAttack can only be applied on instances of IBoundingBox")
499end)
500
501------------------------------ Coordinate Aligners ------------------------------
502local function alignOrigin(ox, oy, ow, oh, x, y, w, h)
503 return {ox + x, oy + y, w, h}
504end
505
506local function alignCenter(ox, oy, ow, oh, x, y, w, h)
507 return {ox + (ow/2) + x, oy + (oh/2) + y, w, h}
508end
509
510local function alignNatural(ox, oy, ow, oh, x, y, w, h)
511 return {ox + (ow/2) + x, oy + (oh/2) + y - (h/2), w, h}
512end
513
514local function alignCoords(self, anchor, area)
515 local ox, oy = self:getPos()
516 local ow, oh = self:getDims()
517 if self:instanceof(Mob) and self:getDir() == Mob.LEFT then
518 local x1, y1, x2, y2 = unpack(area)
519 x2 = x2 - ((x2 - x1) * 2)
520 area = {x1, y1, x2, y2}
521 end
522 if anchor == WeaponDef.anchors.ORIGIN then return alignOrigin(ox, oy, ow, oh, unpack(area))
523 elseif anchor == WeaponDef.anchors.CENTER then return alignCenter(ox, oy, ow, oh, unpack(area))
524 elseif anchor == WeaponDef.anchors.NATURAL then return alignNatural(ox, oy, ow, oh, unpack(area)) end
525end
526
527------------------------------ Transition Runners ------------------------------
528local function checkCollision(self, bb, wpn)
529 local x1, y1, x2, y2 = bb[1], bb[2], bb[1] + bb[3], bb[2] + bb[4]
530 Game.world:queryBoundingBox(x1, y1, x2, y2,
531 box2dWrapper(self, onCollision, wpn))
532
533 if DEBUG.BOUNDING_BOXES then
534 local g = love.graphics
535 g.setColor(1, 1, 1, 1)
536 g.rectangle('fill', unpack(bb))
537 end
538end
539
540local function transInstant(dt, per, self, wpn, prevAnchor, prevArea, anchor, area, dur, freq)
541 prevArea = alignCoords(self, prevAnchor, prevArea)
542 area = alignCoords(self, anchor, area)
543 local bb = area
544
545 checkCollision(self, bb, wpn)
546end
547
548local function transLinearGrow(dt, per, self, wpn, prevAnchor, prevArea, anchor, area, dur, freq)
549 prevArea = alignCoords(self, prevAnchor, prevArea)
550 area = alignCoords(self, anchor, area)
551 local bb = lerpArea(per, prevArea, area)
552
553 checkCollision(self, bb, wpn)
554end
555
556------------------------------ Main Methods ------------------------------
557---Called when a hittable mob is hit.
558function onHit(self, obj, wpn)
559 obj:getHit(self)
560end
561
562---Passed to Box2D as callback; filters collision to hittable mobs only.
563function onCollision(slf, fixt, wpn)
564 local obj = fixt:getUserData()
565 if obj:instanceof(IHittable) then onHit(slf, obj, wpn) end
566 return true
567end
568
569function onAttackDone(slf, wpn)
570 print('done')
571end
572---Fetches the vars for the phase, schedules it, and chains the next phase.
573local function schedulePhase(self, wpn, i)
574 local bx, prevAnchor, prevArea = wpn.hitbox
575 if i == 1 then prevAnchor, prevArea = bx.startAnchor, bx.start
576 else prevAnchor, prevArea = bx[i - 1].anchor, bx[i - 1].area end
577
578 local phase = bx[i]
579 local anchor = phase.anchor
580 local area = phase.area
581 local dur = phase.dur
582 local freq = phase.freq or -1
583 local trans = phase.transition or WeaponDef.transitions.LINEAR_GROW
584
585 local checker;
586 if trans == WeaponDef.transitions.INSTANT then checker = transInstant
587 elseif trans == WeaponDef.transitions.LINEAR_GROW then checker = transLinearGrow end
588
589 local chain;
590 if i < #bx then chain = schedulePhase
591 else chain = onAttackDone end
592
593 Scheduler:gCallEveryFor(freq, dur, checker, {self, wpn, prevAnchor, prevArea, anchor, area, dur, freq},
594 chain, {self, wpn, i + 1})
595
596-- print('-------------')
597-- print('i', i, 'freq', freq, 'dur', dur, 'trans', trans)
598-- print('prevAnchor', prevAnchor, 'prevArea', unpack(prevArea))
599-- print('anchor', anchor, 'area', unpack(area))
600-- print('-------------')
601end
602
603function IMeleeAttack:attack(wpn)
604 schedulePhase(self, wpn, 1)
605end
606
607return IMeleeAttack
608
609
610
611/////////////////Exiting file: IMeleeAttack.lua/////////////////
612//--------------------------------------------------------------------------------------------------------
613/////////////////Entering file: ITickable.lua/////////////////
614
615
616/////////////////Exiting file: ITickable.lua/////////////////
617//--------------------------------------------------------------------------------------------------------
618/////////////////Entering file: box2dMeterTest.lua/////////////////
619local p, g, k = love.physics, love.graphics, love.keyboard
620love.window.setPosition(8, 30, 2)
621local MS, OTHER;
622
623local function createObject(x, y, w, h, world, typ, t)
624 local b = p.newBody(world, x, y, typ)
625 local s = p.newRectangleShape(w / 2, h / 2, w, h)
626 local f = p.newFixture(b, s)
627 local col = ((type(t.col) == 'table' and
628 type(t.col[#t + 1]) == 'table' and
629 t.col[#t + 1]) or t.col) or {0.7, 0.7, 0.7, 1}
630
631 local function draw()
632 g.setColor(col)
633 g.polygon('fill', b:getWorldPoints(s:getPoints()))
634 end
635
636 t[#t + 1] = {b = b, s = s, f = f, draw = draw}
637end
638
639local function createBlock(x, y, w, h, world, t)
640 createObject(x, y, w, h, world, 'static', t)
641end
642local function createEntity(x, y, w, h, world, t)
643 createObject(x, y, w, h, world, 'dynamic', t)
644end
645
646local function set(ms)
647 p.setMeter(ms)
648 print('Set MS to:', p.getMeter())
649end
650
651local world;
652local wall = {}
653local function createWalls()
654 local lx, rx, gx = 2, 20, 2
655 local wy, gy = 2, 16
656 local w, h = 1, 1
657 local ex, ey = 10, 8
658
659 createBlock(lx, wy, w, h * 14, world, wall) --left
660 createBlock(rx, wy, w, h * 14, world, wall) --right
661 createBlock(gx, gy, rx - w, h, world, wall) --ground
662 createEntity(ex, ey, w, h, world, wall)
663
664-- createBlock(320, 512, 32, 32, world, wall)
665-- createEntity(320, 256, 32, 32, world, wall)
666end
667
668local _32 = true
669MS = _32 and 32 or 1
670OTHER = _32 and 1 or 32
671
672local xgravity, ygravity = 0, 9.8 --* MS
673local canSleep = false
674
675function love.load()
676 set(1)
677 print('creating world, setting gravity.')
678 world = p.newWorld(xgravity, ygravity, canSleep)
679 print(world:getGravity())
680
681-- set(OTHER)
682 print('creating walls and entity.')
683 createWalls()
684end
685
686function love.update(dt)
687 world:update(dt)
688end
689
690function love.draw()
691 g.scale(MS, MS)
692 for k, v in ipairs(wall) do v:draw() end
693end
694
695
696
697
698
699
700/////////////////Exiting file: box2dMeterTest.lua/////////////////
701//--------------------------------------------------------------------------------------------------------
702/////////////////Entering file: conf.lua/////////////////
703function love.conf(t)
704 -- Commented out defaults shown below.
705 -- See https://www.love2d.org/wiki/Config_Files for more information.
706
707 -- t.identity = nil -- The name of the save directory (string)
708 -- t.version = "0.10.2" -- The L�VE version this game was made for (string)
709 t.console = true -- Attach a console (boolean, Windows only)
710 -- t.accelerometerjoystick = true -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean)
711 -- t.externalstorage = false -- True to save files (and read from the save directory) in external storage on Android (boolean)
712 -- t.gammacorrect = false -- Enable gamma-correct rendering, when supported by the system (boolean)
713
714 t.window.title = "Entity-Component Based 2D GameEngine" -- The window title (string)
715 -- t.window.icon = nil -- Filepath to an image to use as the window's icon (string)
716 -- t.window.width = 800 -- The window width (number)
717 -- t.window.height = 600 -4- The window height (number)
718 -- t.window.borderless = false -- Remove all border visuals from the window (boolean)
719 -- t.window.resizable = false -- Let the window be user-resizable (boolean)
720 -- t.window.minwidth = 1 -- Minimum window width if the window is resizable (number)
721 -- t.window.minheight = 1 -- Minimum window height if the window is resizable (number)
722 -- t.window.fullscreen = false -- Enable fullscreen (boolean)
723 -- t.window.fullscreentype = "desktop" -- Choose between "desktop" fullscreen or "exclusive" fullscreen mode (string)
724 -- t.window.vsync = true -- Enable vertical sync (boolean)
725 -- t.window.msaa = 0 -- The number of samples to use with multi-sampled antialiasing (number)
726 -- t.window.display = 1 -- Index of the monitor to show the window in (number)
727 -- t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean)
728 -- t.window.x = nil -- The x-coordinate of the window's position in the specified display (number)
729 -- t.window.y = nil -- The y-coordinate of the window's position in the specified display (number)
730
731 -- t.modules.audio = true -- Enable the audio module (boolean)
732 -- t.modules.event = true -- Enable the event module (boolean)
733 -- t.modules.graphics = true -- Enable the graphics module (boolean)
734 -- t.modules.image = true -- Enable the image module (boolean)
735 -- t.modules.joystick = true -- Enable the joystick module (boolean)
736 -- t.modules.keyboard = true -- Enable the keyboard module (boolean)
737 -- t.modules.math = true -- Enable the math module (boolean)
738 -- t.modules.mouse = true -- Enable the mouse module (boolean)
739 -- t.modules.physics = true -- Enable the physics module (boolean)
740-- t.modules.sound = true -- Enable the sound module (boolean)
741 -- t.modules.system = true -- Enable the system module (boolean)
742 -- t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update
743 -- t.modules.touch = true -- Enable the touch module (boolean)
744 -- t.modules.video = true -- Enable the video module (boolean)
745 -- t.modules.window = true -- Enable the window module (boolean)
746 -- t.modules.thread = true -- Enable the thread module (boolean)
747end
748
749
750/////////////////Exiting file: conf.lua/////////////////
751//--------------------------------------------------------------------------------------------------------
752/////////////////Entering file: Game.lua/////////////////
753local class = require "libs.cruxclass"
754local Timer = require "utils.Timer"
755
756--local Thing = require "template.Thing"
757--local IBoundingBox = require "behavior.IBoundingBox"
758--local Registry = require "istats.Registry"
759
760local Game = class("Game")
761function Game:init()
762 love.physics.setMeter(1)
763 self.world = love.physics.newWorld(Game.GRAVITY_X, Game.GRAVITY_Y)
764
765 self.timer = Timer()
766end
767
768---Constants
769
770Game.GRID = 32
771Game.MS = Game.GRID
772
773Game.GRAVITY_X = 0
774Game.GRAVITY_Y = 25
775
776---Core
777function Game:tick(dt)
778 self.world:update(dt)
779 self.timer:tick(dt)
780end
781
782function Game:draw()
783end
784
785---Utils
786function Game:scaledSnap(x)
787 return math.floor(x / Game.GRID) * Game.GRID
788end
789
790function Game:snap(x)
791 return math.floor(x)
792end
793
794---Getters
795function Game:getLoadedWorld()
796 return self.world
797end
798
799function Game:getM()
800 return self.m
801end
802
803--function Game:getGridW()
804-- return Game.GRID
805--end
806--
807--function Game:getGridH()
808-- return Game.GRID
809--end
810
811return Game()
812
813--[[
814Needed methods:
815
816getLoadedWorld
817getGridW
818getGridH
819
820Note: Is a singleton
821
822return Game() -- this script should return an instance of
823 Game, the only one; providing no access to the class's init.
824 (Possibly requiring to forbid access to the class in it's entirety)
825--]]
826
827/////////////////Exiting file: Game.lua/////////////////
828//--------------------------------------------------------------------------------------------------------
829/////////////////Entering file: Keybinds.lua/////////////////
830local class = require "libs.cruxclass"
831
832local Keybinds = class("Keybinds")
833function Keybinds:init(k, code, rpt)
834 error "Cannot instantise static class."
835end
836
837Keybinds.UP = 'w'
838Keybinds.DOWN = 's'
839Keybinds.LEFT = 'a'
840Keybinds.RIGHT = 'd'
841
842Keybinds.SPRINT= 'lshift'
843
844Keybinds.JUMP = 'space'
845
846return Keybinds
847
848
849/////////////////Exiting file: Keybinds.lua/////////////////
850//--------------------------------------------------------------------------------------------------------
851/////////////////Entering file: MultiState.lua/////////////////
852local class = require "libs.cruxclass"
853local State = require "core.State"
854
855---Constructor
856local MultiState = class("MultiState", State)
857function MultiState:init(initialState)
858 State.init(self)
859 self.state = {}
860end
861
862---Constants
863MultiState.DEFAULT_VAL = false
864
865---Main Methods
866function MultiState:set(s, v)
867 if type(v) == 'nil' then v = true end
868 self.state[s], v = v, self.state[s]
869 return self.state[s] ~= v
870end
871
872function MultiState:unset(s)
873 return self:set(s, false)
874end
875
876function MultiState:get(s)
877 return self.state[s]
878end
879
880---Util Methods
881function MultiState:noneof(...)
882 local all = {...}
883 for _, v in ipairs(all) do
884 if self.state[v] == true then return false end
885 end
886 return true
887end
888
889function MultiState:anyof(...)
890 local all = {...}
891 for _, v in ipairs(all) do
892 if self.state[v] == true then return true end
893 end
894 return false
895end
896
897function MultiState:is(s)
898 return self.state[s]
899end
900
901function MultiState:isnot(s)
902 return not self.state[s]
903end
904
905return MultiState
906
907/////////////////Exiting file: MultiState.lua/////////////////
908//--------------------------------------------------------------------------------------------------------
909/////////////////Entering file: State.lua/////////////////
910local class = require "libs.cruxclass"
911
912---Constructor
913local State = class("State")
914function State:init(initialState)
915 self.state = initialState or State.DEFAULT_INITIAL
916end
917
918---Constants
919State.DEFAULT_MAX = 10
920State.DEFAULT_INITIAL = 1
921---Main Methods
922function State:set(s)
923 self.state, s = s, self.state
924 return self.state == s
925end
926
927function State:get()
928 return self.state
929end
930
931---Util Methods
932function State:create(n)
933 n = n or State.DEFAULT_MAX
934 local t = {}
935 for i = 1, n do
936 t[i] = i
937 end
938 return unpack(t)
939end
940
941function State:noneof(...)
942 local all = {...}
943 for _, v in ipairs(all) do
944 if self.state == v then return false end
945 end
946 return true
947end
948
949function State:anyof(...)
950 local all = {...}
951 for _, v in ipairs(all) do
952 if self.state == v then return true end
953 end
954 return false
955end
956
957function State:is(s)
958 return self.state == s
959end
960
961function State:isnot(s)
962 return self.state ~= s
963end
964
965return State
966
967/////////////////Exiting file: State.lua/////////////////
968//--------------------------------------------------------------------------------------------------------
969/////////////////Entering file: BoundingBox.lua/////////////////
970local class = require "libs.cruxclass"
971local Game = require "core.Game"
972local EShapes = require "template.EShapes"
973
974---Private Methods
975local function getShape(s, a, b, c)
976 local p, e, f = love.physics, EShapes
977
978 if s == e.RECT then f = p.newRectangleShape
979 elseif s == e.CIRCLE then f = p.newCircleShape
980 elseif s == e.POLY then f = p.newPolygonShape end
981 -- TODO: add more shapes
982
983 return f(a, b, c)
984end
985
986local function checkShapeDat(st, d)
987 d = d:lower()
988 if st == EShapes.RECT then
989 return d == 'w' or d == 'h' or d == 'angle'
990 elseif st == EShapes.CIRCLE then
991 return d == 'r'
992 end
993 return false
994end
995
996local BoundingBox = class("Body")
997
998--- @function [parent=#template.BoundingBox] init Construct a new BoundingBox.
999-- @param #love.physics#World wThe world to create the body in.
1000-- @param #number x The x position of the bounding box (top left origin).
1001-- @param #number y The y position of the bounding box (top left origin).
1002-- @param #love.physics#BodyType type The type of the body; static, dynamic, or kinematic.
1003-- @param #template.EShapes shapeType The shape of the body (Rect, Circle, Poly, Precise, etc...).
1004-- @param #number a The first paramater to pass to the shape. Rect = w; Circle = r; Poly = vertices.
1005-- @param #number b The second paramater to pass to the shape. Rect = h;
1006-- @param #number c The third paramater to pass to the shape. Rect = angle;
1007
1008function BoundingBox:init(w, x, y, type, shapeType, a, b, c)
1009 self.shapeType = shapeType
1010 self.a, self.b, self.c = a, b, c
1011 self.b = love.physics.newBody(w, x, y, type)
1012 self.s = getShape(shapeType, a, b, c)
1013 self.f = love.physics.newFixture(self.b, self.s)
1014
1015 f = love.physics.newBody();
1016 f = love.physics.newRectangleShape();
1017 f = love.physics.newCircleShape();
1018end
1019
1020---Common position getters
1021function BoundingBox:getX() return self.b:getX() end
1022function BoundingBox:getY() return self.b:getY() end
1023function BoundingBox:getPos() return self.b:getX(), self.b:getY() end
1024
1025---Rectangle data getters
1026function BoundingBox:getW()
1027 assert(checkShapeDat(self.shapeType, 'w'), "getW can only be called on rectangular BoundingBoxes.")
1028 return self.a
1029end
1030
1031function BoundingBox:getH()
1032 assert(checkShapeDat(self.shapeType, 'h'), "getH can only be called on rectangular BoundingBoxes.")
1033 return self.b
1034end
1035
1036function BoundingBox:getAngle()
1037 assert(checkShapeDat(self.shapeType, 'angle'), "getAngle can only be called on rectangular BoundingBoxes.")
1038 return self.c
1039end
1040
1041function BoundingBox:getDims()
1042 assert(checkShapeDat(self.shapeType, 'w')
1043 and checkShapeDat(self.shapeType, 'h')
1044 and checkShapeDat(self.shapeType, 'angle'),"getDims can only be called on rectangular BoundingBoxes.")
1045 return self.a, self.b, self.c or 0
1046end
1047
1048---Rectangle data setters
1049function BoundingBox:setW(w)
1050 assert(checkShapeDat(self.shapeType, 'w'), "getW can only be called on rectangular BoundingBoxes.")
1051 self.a = w
1052end
1053
1054function BoundingBox:setH(h)
1055 assert(checkShapeDat(self.shapeType, 'h'), "getH can only be called on rectangular BoundingBoxes.")
1056 self.b = h
1057end
1058
1059function BoundingBox:setAngle(a)
1060 assert(checkShapeDat(self.shapeType, 'angle'), "getAngle can only be called on rectangular BoundingBoxes.")
1061 self.c = a
1062end
1063
1064function BoundingBox:setDims(w, h, a)
1065 assert(checkShapeDat(self.shapeType, 'w')
1066 and checkShapeDat(self.shapeType, 'h'), "getDims can only be called on rectangular BoundingBoxes.")
1067 self.a, self.b, self.c = w, h, a
1068end
1069
1070---Circle data getters
1071function BoundingBox:getRadius()
1072 assert(checkShapeDat(self.shapeType, 'r'), "getRadius can only be called on circular BoundingBoxes.")
1073 return self.a
1074end
1075
1076function BoundingBox:getDiameter()
1077 return self:getRadius() * 2
1078end
1079
1080---Object-common methods
1081function BoundingBox:clone()
1082 return BoundingBox(self.x, self.y, self.b:getType(),
1083 self.shapeType, self.a, self.b, self.c)
1084end
1085
1086return BoundingBox
1087
1088/////////////////Exiting file: BoundingBox.lua/////////////////
1089//--------------------------------------------------------------------------------------------------------
1090/////////////////Entering file: Player.lua/////////////////
1091local class = require "libs.cruxclass"
1092local Entity = require "template.Entity"
1093local IHealth = require "behavior.IHealth"
1094
1095local IEventHandler = require "evsys.IEventHandler"
1096local KeypressEvent = require "evsys.input.KeypressEvent"
1097local Keybinds = require "core.Keybinds"
1098
1099local Game = require "core.Game"
1100--local Registry = require "istats.Registry"
1101
1102
1103local Player = class("Player", Entity):include(IEventHandler)
1104
1105Player.LEFT = 1
1106Player.RIGHT = 2
1107function Player:init(x, y)
1108 Entity.init(self, "player", x, y)
1109 self.dir = Player.RIGHT
1110
1111 local b = self.body
1112 print('mass', b:getMass())
1113-- print('density', b:getMass())
1114-- print('friction', b:getMass())
1115
1116 self.g = 0
1117 self.funcs = {}
1118 self.times = {}
1119 self.cleanup = {}
1120end
1121local move;
1122function Player:tick(dt)
1123 local k = love.keyboard
1124
1125 if k.isDown(Keybinds.LEFT) then move(self, -self.speed, 0) end
1126 if k.isDown(Keybinds.RIGHT) then move(self, self.speed, 0) end
1127
1128
1129-- local maxVel = self.speed / self.bodyMass
1130-- local f =
1131
1132-- local vx, vy = self.body:getLinearVelocity()
1133-- local fx, fy = 0, 0
1134-- if k.isDown(Keybinds.LEFT) then
1135-- fx = -self.speed * 1
1136-- self.dir = Player.LEFT
1137-- end
1138-- if k.isDown(Keybinds.RIGHT) then
1139-- fx = self.speed * 1
1140-- self.dir = Player.RIGHT
1141-- end
1142-- self.body:applyLinearImpulse(fx, fy)
1143
1144 self:updateFuncs(dt)
1145end
1146
1147function Player:jump()
1148-- local vx, vy = self.body:getLinearVelocity()
1149-- vy = vy - self.jumpHeight
1150-- self.body:setLinearVelocity(vx, vy)
1151 self.body:applyLinearImpulse(0, -self.jumpHeight * 7.5)
1152end
1153
1154function Player:callFor(s, f, c)
1155 local i = false;
1156 for k, v in ipairs(self.funcs) do
1157 if v == f then i = k end
1158 end
1159 if not i then
1160 table.insert(self.funcs, f)
1161 table.insert(self.times, s)
1162 table.insert(self.cleanup, c or function() end)
1163 end
1164end
1165
1166function Player:updateFuncs(dt)
1167 if #self.funcs > 0 then
1168 for k, f in ipairs(self.funcs) do
1169 self.times[k] = self.times[k] - dt
1170 if self.times[k] <= 0 then
1171 self.cleanup[k]()
1172 table.remove(self.funcs, k)
1173 table.remove(self.times, k)
1174 table.remove(self.cleanup, k)
1175 else f() end
1176 end
1177 end
1178end
1179
1180local function reqF(s, v)
1181 local x = s - v; local dt, m = 1/60, 1
1182 if (0 > s and s > v) or (0 < s and s < v) then x = 0 end
1183 local a = x/dt
1184 local f = a*m
1185 return f
1186end
1187
1188function move(obj, sx, sy)
1189 local vx, vy = obj.body:getLinearVelocity()
1190 local fx, fy = reqF(sx, vx), 0--reqF(sy, vy)
1191 local str = string.format('about to apply force of: %.3f\t\t%.f', fx, fy)
1192 print(str)
1193 print('\t --- \t', 'sx', sx, 'vx', vx)
1194 obj.body:applyForce(fx, fy)
1195-- obj.body:setLinearVelocity(sx, sy)
1196end
1197
1198--[[
1199 final equation:
1200 [dif] x = s - v
1201 if (s neg AND s > v) OR (s pos AND s < v)
1202 x = 0
1203 f = toForce(x)
1204 body->applyForce(f)
1205
1206 goal:
1207 move -> vel >= speed (aka max moving velocity)
1208 get current vel
1209 get goal vel (speed)
1210 if vel >= speed ;
1211 do nothing
1212 if vel < speed ;
1213 apply enough force to accelerate
1214 to speed in 1 tick
1215 => go from 'goal velocity' (speed) to force to apply
1216
1217 physics cheatsheet:
1218 a = v/t
1219 f = am
1220
1221 f = ma
1222 v = at
1223 a = dv/dt ; dv = a * dt
1224
1225 --------- examples --------------
1226
1227 -- right
1228 v = 2 ; s = 3 -> 1
1229 v = 4 ; s = 3 -> 0
1230
1231 dif: s - v
1232 [3 - 2] 1 (apply)
1233 [3 - 4] -1 (x < v)
1234
1235 -- left
1236 v = -2 ; s = -3 -> -1
1237 v = -4 ; s = -3 -> 0
1238
1239 dif: s - v
1240 [-3 - -2] -1 (apply)
1241 [-3 - -4] 1 (x > v)
1242
1243 -- right TO left
1244 v = 2 ; s = -3 -> -5
1245 v = 4 ; s = -3 -> -7
1246
1247 dif: s - v
1248 [-3 - 2] -5 (apply)
1249 [-3 - 4] -7 (apply)
1250
1251 -- left TO right
1252 v = -2 ; s = 3 -> 5
1253 v = -4 ; s = 3 -> 7
1254
1255 dif: s - v
1256 [3 - -2] 5 (apply)
1257 [3 - -4] 7 (apply)
1258
1259 equation:
1260 [dif] x = s - v
1261 if (s neg AND s > v) OR (s pos AND s < v)
1262 x = 0
1263 f = toForce(x)
1264 body->applyForce(f)
1265--]]
1266
1267local function halt(self)
1268 local vx, vy = self.body:getLinearVelocity()
1269 vx, vy = 0, 0
1270 self.body:setLinearVelocity(vx, vy)
1271end
1272
1273---@Callback
1274Player:attach(KeypressEvent, function(self, e)
1275-- if e.k == Keybinds.JUMP then
1276-- self:jump()
1277-- end
1278
1279 if e.k == 'v' then
1280 local vx, vy = self.body:getLinearVelocity()
1281 vy = -10
1282 self.body:setLinearVelocity(vx, vy)
1283 end
1284
1285 if e.k == 'f' then
1286 self.body:applyForce(0, -300)
1287 end
1288
1289 if e.k == 't' then
1290 self:callFor(0.1, function()
1291 self.body:applyForce(0, -100)
1292 end)
1293 end
1294
1295 if e.k == 'i' then
1296 self.body:applyLinearImpulse(0, -10)
1297 end
1298
1299 if e.k == 'left' then
1300 self:callFor(3, function()
1301 move(self, -self.speed, 0)
1302 end, function()
1303 halt(self)
1304 end)
1305-- move(self, -self.speed, 0)
1306 end
1307
1308 if e.k == 'right' then
1309 self:callFor(3, function()
1310 move(self, self.speed, 0)
1311 end, function()
1312 halt(self)
1313 end)
1314 end
1315
1316 if e.k == 'g' then
1317 self:callFor(3, function()
1318 self.g = self.g + 1
1319 end, function()
1320 self.g = 0
1321 end)
1322 end
1323end)
1324
1325return Player
1326
1327/////////////////Exiting file: Player.lua/////////////////
1328//--------------------------------------------------------------------------------------------------------
1329/////////////////Entering file: Registry.lua/////////////////
1330local class = require "libs.cruxclass"
1331
1332local FilepathUtils = require "utils.FilepathUtils"
1333local EShapes = require "behavior.EShapes"
1334local WeaponDef = require "template.WeaponDef"
1335
1336--local Game = require "core.Game"
1337
1338------------------------------ Constructor ------------------------------
1339local Registry = class("Registry")
1340function Registry:init()
1341 error "Attempting to initialize static class."
1342end
1343
1344------------------------------ Data Methods ------------------------------
1345local function data(d)
1346 local t = Registry.static
1347 local id = d[1]
1348 t[id] = t[id] or {}
1349
1350 for k, v in pairs(d) do
1351 if k ~= 1 then t[id][k] = v end
1352 end
1353end
1354
1355local function loadAllData()
1356 local lovePath = FilepathUtils.love.path.istatsData
1357 local luaPath = FilepathUtils.lua.path.istatsData
1358 local files = love.filesystem.getDirectoryItems(lovePath)
1359
1360 print("Loading all data.")
1361 for k, v in ipairs(files) do
1362 print(k, v)
1363 if v:sub(1, 1) ~= '.' then
1364 local type = love.filesystem.getInfo(lovePath .. v).type
1365 if type == 'file' then love.filesystem.load(lovePath .. v)() end
1366 end
1367 end
1368 print("Finished loading all data.")
1369end
1370
1371------------------------------ Data ------------------------------
1372_G.data = data
1373_G.WeaponDef = WeaponDef
1374loadAllData()
1375_G.data = nil
1376_G.WeaponDef = nil
1377
1378------------------------------ Defaults ------------------------------
1379local D_IDV, D_INSTV
1380do
1381 D_IDV = require "istats.defaults.idVars"
1382 D_INSTV = require "istats.defaults.instanceVars"
1383 local t = require "istats.defaults.masks"
1384 D_IDV.categories, D_IDV.masks = t.categories, t.masks
1385end
1386
1387
1388
1389Registry.defaults = {}
1390Registry.defaults.idVars = D_IDV
1391Registry.defaults.instVars = D_INSTV
1392
1393------------------------------ InstanceVars Applier ------------------------------
1394function Registry.static:applyStat(id, inst, stat)
1395 local applied = false
1396 if D_INSTV[stat] then --Apply defaults
1397 for k, v in pairs(D_INSTV[stat]) do inst[k] = v end
1398 applied = true
1399 end
1400
1401 if self[id] and self[id].stats and self[id].stats[stat] then --Apply idata
1402 for k, v in pairs(self[id].stats[stat]) do inst[k] = v end
1403 applied = true
1404 end
1405 return applied
1406end
1407
1408------------------------------ Thing ------------------------------
1409function Registry.static:getName(id)
1410 return self[id] and self[id].name or "$" .. id
1411end
1412
1413function Registry.static:getDesc(id)
1414 return self[id] and self[id].desc or self.defaults.DESC
1415end
1416
1417------------------------------ Rendering ------------------------------
1418function Registry.static:getSpr(id)
1419
1420end
1421
1422------------------------------ IBoundingBox ------------------------------
1423function Registry.static:getBodyDensity(id)
1424 return self[id] and self[id].body and self[id].body.density or D_IDV.BODY_DENSITY
1425end
1426
1427function Registry.static:getBodyMass(id)
1428 return self[id] and self[id].body and self[id].body.mass or D_IDV.BODY_MASS
1429end
1430
1431function Registry.static:getBodyFriction(id)
1432 return self[id] and self[id].body and self[id].body.friction or D_IDV.BODY_FRICTION
1433end
1434
1435function Registry.static:getBodyRestitution(id)
1436 return self[id] and self[id].body and self[id].body.rest or D_IDV.BODY_RESTITUTION
1437end
1438
1439function Registry.static:getShapeType(id)
1440 return (self[id] and self[id].body and
1441 EShapes[self[id].body.shape or ""]) or D_IDV.SHAPE_TYPE
1442end
1443
1444function Registry.static:getShapeDat(id)
1445 if self[id] and self[id].body then
1446 local b = self[id].body
1447 return b.w or b.r or D_IDV.SHAPE_A, b.h or D_IDV.SHAPE_B
1448 else return D_IDV.SHAPE_A, D_IDV.SHAPE_B end
1449end
1450
1451------------------------------ IHealth ------------------------------
1452function Registry.static:getMaxHealth(id)
1453 return self[id] and self[id].maxHealth or D_IDV.MAX_HEALTH
1454end
1455
1456return Registry
1457
1458/////////////////Exiting file: Registry.lua/////////////////
1459//--------------------------------------------------------------------------------------------------------
1460/////////////////Entering file: RegistryDefaultLoadingDocsIsh.lua/////////////////
1461local EShapes = require "behavior.EShapes"
1462
1463-- global r is used by the registry to collect the defaults
1464
1465------------------------------ Thing ------------------------------
1466t = r.idv.Thing -- r's __index metamethod will create r[k] = k and return it
1467t.NAME = "Unnamed"
1468t.DESC = "Missing desc."
1469
1470t = r.instv.Thing
1471t.durability = 20
1472
1473------------------------------ Rendering ------------------------------
1474t = r.IDrawable --same case as above
1475
1476t.SPR = nil
1477t.width = topx(16) --some global methods are passed for ease
1478t.height = topx(16)
1479
1480function t.__f:width(id) --the table returned by r's index metamethod
1481 local w --has it's metatable set to, if t.__f is nil:
1482 w = self:getSpr(id):getWidth() --declare t.__f as a table and return it.
1483 return w --if t.__f is explicitly declared as a new table,
1484end --or has any table value assigned to it, it's fine.
1485 --__f itself has no metatable.
1486function t.__f:height(id) --the registry only looks at __f, if any,
1487 local h --for default-defined functions
1488 h = self:getSpr(id):getHeight()
1489 return h
1490end
1491
1492--[[
1493t.__f is used for default-fallbacks: is called with f(instance, id, t, k, v)
1494 - If present for t.__f[k], is indented into getVar() as the default-fallback.
1495 - Else, the native-default is indented directly.
1496
1497t.__d is used for data-computation: is called with f(instance, id, t, k, v, datum)
1498 - If present for t.__d[k], is called with the native-default and datum,
1499 It's return value is applied into the instance.
1500 - Else, the datum is applied directly, else, the native-default is applied.
1501
1502General:
1503 1- Take priority over a native-default.
1504 2- Are passed the var (k) and native-default (v), if any.
1505 3- [__d only] Are passed the value from the datapack (datum), if any.
1506
1507 Terminology:
1508 r.t = Registry.defaults.i__v.className
1509
1510 instance = the instance being instantiated
1511 t = r.t --aka the class's defaults.i__x
1512 k = var --aka what is indexed with in r.t[k]
1513 v = r.t[k] --aka the value of var.
1514 native-default = r.t[k] --aka v
1515 default-fallback = r.t.__f[k]
1516 default-compute = r.t.__f[k]
1517 datum = r.data.t[k] --aka the datapack value of var.
1518
1519--]]
1520------------------------------ IBoundingBox ------------------------------
1521t.BODY_DENSITY = nil
1522t.BODY_MASS = nil --As to use Box2D's internal mass computation.
1523t.BODY_FRICTION = nil
1524t.BODY_RESTITUTION = nil
1525t.SHAPE_TYPE = EShapes.RECT
1526t.SHAPE_A = 1
1527t.SHAPE_B = 1
1528
1529------------------------------ IHealth ------------------------------
1530t.MAX_HEALTH = 100
1531
1532return t
1533
1534
1535/////////////////Exiting file: RegistryDefaultLoadingDocsIsh.lua/////////////////
1536//--------------------------------------------------------------------------------------------------------
1537/////////////////Entering file: Scheduler.lua/////////////////
1538local class = require "libs.cruxclass"
1539
1540------------------------------ Helper Methods ------------------------------
1541local getTime = love.timer.getTime
1542local ins = table.insert
1543local rem = table.remove
1544
1545local function push(t, wait, interval, timeout, stamp, funcs, args)
1546
1547 for k, v in ipairs(t) do
1548 ins(t[k], args[k])
1549 end
1550end
1551
1552------------------------------ Constructor ------------------------------
1553local Scheduler = class("Scheduler")
1554function Scheduler:init()
1555 self.after = {wait = {}, stamp = {}, func = {}, args = {}}
1556 self.ffor = {timeout = {}, stamp = {}, func = {}, args = {}}
1557 self.every = {interval = {}, stamp = {}, func = {}, args = {}}
1558 self.everyFor = {interval = {}, timeout = {}, stamp = {}, func = {}, args = {}}
1559end
1560
1561------------------------------ Main Methods ------------------------------
1562function Scheduler:tick(dt)
1563
1564end
1565
1566------------------------------ Schedule Methods ------------------------------
1567function Scheduler:callAfter(wait, func, ...)
1568 push(self.after, wait, getTime(), func, {...})
1569-- local t = self.after
1570-- ins(t.wait, wait)
1571-- ins(t.stamp, getTime())
1572-- ins(t.func, func)
1573-- ins(t.args, {...})
1574end
1575
1576function Scheduler:callFor(timeout, func, ...)
1577 push(self.ffor, timeout, getTime(), func, {...})
1578end
1579
1580function Scheduler:callEvery(interval, func, ...)
1581
1582end
1583
1584function Scheduler:callEveryFor(interval, timeout, func, ...)
1585
1586end
1587return Scheduler()
1588
1589/////////////////Exiting file: Scheduler.lua/////////////////
1590//--------------------------------------------------------------------------------------------------------
1591/////////////////Entering file: WorldObj.lua/////////////////
1592local class = require "libs.cruxclass"
1593local Thing = require "template.Thing"
1594local IBoundingBox = require "behavior.IBoundingBox"
1595
1596local WorldObj = class("WorldObj", Thing):include(IBoundingBox)
1597function WorldObj:init(id, x, y)
1598 Thing.init(self, id)
1599
1600
1601
1602 self.x, self.y = x, y
1603 self.bb = Rectangle(x, y) --TODO: w/h
1604end
1605
1606--- @param #WorldObj o -- a WorldObj, or table of them.
1607function WorldObj:intersects(o) error("Abstract method not overriden.") end -- o/false
1608
1609function WorldObj:getX() return self.bb:getX() end
1610function WorldObj:getY() return self.bb:getY() end
1611function WorldObj:getW() return self.bb:getW() end
1612function WorldObj:getH() return self.bb:getH() end
1613
1614function WorldObj:getCoords() return self.bb:getCoords() end
1615function WorldObj:getSize() return self.bb:getSize() end
1616function WorldObj:getBounds() return self.bb:getBounds() end
1617function WorldObj:getBoundingBox() return self.bb end
1618function WorldObj:cloneBoundingBox() return self.bb:clone() end
1619
1620function WorldObj:setX(x) self.bb:setX(x) end
1621function WorldObj:setY(y) self.bb:setY(y) end
1622function WorldObj:setCoords(a, b)
1623 if type(a) == 'table' and a.instanceof and a.instanceof(Vector) then
1624 self.bb:setCoords(a[1], a[2])
1625 else self.bb:setCoords(a, b) end
1626end
1627
1628return WorldObj
1629
1630/////////////////Exiting file: WorldObj.lua/////////////////
1631//--------------------------------------------------------------------------------------------------------
1632/////////////////Entering file: InventoryDocs.lua/////////////////
1633--[[
1634
1635
1636
1637------------------------------ Overview / tl;dr ------------------------------
1638Item: Any inventory item, including any metadata it requires (durability, etc...)
1639
1640ItemStack: Holds an item; multiple, but only if stackable and with matching data/metadata.
1641 Holds a reference to it's parent slot (Or ItemDrop, if in-world).
1642 Used by slots to hold items.
1643
1644Slot: Holds an ItemStack.
1645 Holds a reference to it's parent inventory, if any.
1646 API offers/manages interaction with:
1647 - Other ItemStacks. E.g. Stacking items, auto insertion, etc...
1648 - Other Slots. E.g Mouse slot interaction (sorting?).
1649 - Filtering
1650
1651
1652IInventory: Holds multiple Slots, manages interaction between them.
1653 Holds a reference to it's parent, if any; Can be an IInventory or Thing (perhaps also other things).
1654 API offers/manages interaction with:
1655 - Direct interaction with slots:
1656 -> Based on index. E.g. Mouse slot, specific-inserters.
1657 -> Based on contents (querying). E.g. A battery querying chargables.
1658 + More querying filters/patterns.
1659 - Interaction with inventory as a whole. E.g. Hoppers, auto-filling an inventory, etc...
1660 - Global operations on all Slots. E.g (un)filter all, clear all, restock all, etc...
1661
1662Note: The mouse slot is a single slot (? single-slot-inv ?) belonging to the player,
1663 Not treated specially. Not different.
1664
1665ItemDrop: Holds a single ItemStack, exists in the world.
1666 Used to drop ItemStacks into the world.
1667 [debate] Auto-merges with nearby identical ItemDrops (minecraft-style).
1668
1669
1670ITickable: The same interface used by WorldObj's.
1671 Is attached to Item's.
1672 Whenever a new ItemStack is assigned to a Slot,
1673 It checks if that ItemStack's Item is tickable, if yes,
1674 It adds it to it's parent's list of tickables, and notifies it. (same for removal)
1675 If an inventories tickables list "becomes" non-empty, it subscribes to ticking,
1676 If an inventories tickables list "becomes" empty, it unsubscribes from ticking,
1677 (inventories are ticked by some global inv-ticker in the world / loaded-chunks)
1678
1679 (? if a Slot's (?/ItemStack's?) parent is nil, it never gets ticked, or subs directly. ?)
1680
1681
1682TODO: Design Drawing/GUI interfaces.
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703--]]
1704
1705/////////////////Exiting file: InventoryDocs.lua/////////////////
1706//--------------------------------------------------------------------------------------------------------
1707/////////////////Entering file: RegistryDocs.lua/////////////////
1708--[=[
1709
1710TODO: Optimize operation of the registry.
1711
1712idVars:
1713 - Attached to id, read-only.
1714 - Classes/Interfaces requiring idVars must define their defaults in:
1715 istats/defaults/idv.
1716
1717classVars: ??? Needed ???
1718 - Attached to class, aka static, read-write.
1719
1720instanceVars:
1721 - Applied onto the instance, read-write, each instant holds its own version.
1722 - Classes/Interfaces requiring idVars must define their defaults in:
1723 istats/defaults/instv.
1724
1725
1726
1727Registry init:
1728 Iterate over the following folders, indexing into the following:
1729 defaults/ -> Reg.defaults
1730 data/ -> Reg.data
1731 Note: data is split into idv/instv based on the provided defaults.
1732 A datum with no underlying default is ignored!
1733 TODO: Change it so that extra datums are considered instvs?
1734
1735 Extra:
1736 defaults can be a function
1737
1738Registry usage:
1739 1- Thing (or child) calls Registry:apply(self, id). --initial call.
1740 2- The hierarchy of inst is explored to gather all classes/interfaces,
1741 def a table of their __name__ fields as h. --fetch hierarchy.
1742
1743 3- All entries defined by the given class's defaults get ---idv
1744 getters created for them in the instance: --create getters, with defaults-fallback.
1745 --(iterating over h) --
1746 className = h[i] --iterate all defaults of the given hierarchy.
1747 def = Reg.defaults.idv[className] --fetch all default idvs of className (current iteration).
1748 dat = Reg.data --access ALL registry data. (not sectioned into idv/instv)
1749 for k, v in ipairs(def) --iterating the defaults of a given class.
1750 fstr = "get" .. capitalize(k) --Format getter name.
1751 instance[fstr] = function() return dat[id][k] or v end --set instance.getVar to return the data[id][var] or defaults.idv[className][var].
1752 --def[k] CAN be a func which computes the value based on instance and id.
1753 4- Similar to the above, except the vars are:
1754 - Applied directly to instance, instead of being wrapped in getters:
1755 (iterating over h ; className)
1756 className = h[i] --iterate all defaults of the given hierarchy.
1757 def = Reg.defaults.instv[className] --fetch all default instvs of className (current iteration).
1758 dat = Reg.data --access ALL registry data. (not sectioned into idv/instv)
1759 for k, v in ipairs(def) --iterating the defaults of a given class.
1760 instance[k] = dat[id][k] or v --set instance[var] to data[id][var] or defaults.intsv[className][var]
1761
1762
1763================ OUTDATED ================ ALSO TERMINOLOGY CHANGED GREATLY ================
1764In-place functions:
1765 t.__f is used for default-fallbacks: is called with f(id, instance, t, k, v)
1766 - If present for t.__f[k], is indented into getVar() as the default-fallback.
1767 - Else, the native-default is indented directly.
1768
1769 t.__d is used for data-computation: is called with f(instance, id, t, k, v, datum)
1770 - If present for t.__d[k], is called with the native-default and datum,
1771 It's return value is applied into the instance.
1772 - Else, the datum is applied directly, else, the native-default is applied.
1773
1774 General:
1775 1- Take priority over a native-default.
1776 2- Are passed the var (k) and native-default (v), if any.
1777 3- [__d only] Are passed the value from the datapack (datum), if any.
1778
1779 Terminology:
1780 r.t = Registry.defaults.i__v.className
1781
1782 instance = the instance being instantiated
1783 t = r.t --aka the class's defaults.i__x
1784 k = var --aka what is indexed with in r.t[k]
1785 v = r.t[k] --aka the value of var.
1786 native-default = r.t[k] --aka v
1787 default-fallback = r.t.__f[k]
1788 default-compute = r.t.__f[k]
1789 datum = r.data.t[k] --aka the datapack value of var.
1790
1791Templates:
1792 Used for:
1793 1- Data-driven object creation / during runtime.
1794 template = class
1795 2- Data-driven template creation (combining) during runtime.
1796 template = {class, interface0, interface1, ...}
1797
1798 Registry:create(id, args)
1799 1- Uses the id to fetch a template.
1800 2- Fetches the [base] class from template.
1801 If any mixins are present, includes them into the class, in order.
1802 3- return combinedClass(args) --calling the constructor of the [base] class.
1803 4-
1804 TODO: Figure out how to pass args/initial-values to the given mixins, if any.
1805
1806--]=]
1807
1808
1809
1810/////////////////Exiting file: RegistryDocs.lua/////////////////
1811//--------------------------------------------------------------------------------------------------------
1812/////////////////Entering file: artDocs.lua/////////////////
1813--[[
1814@Jo
1815PS: Don't be offended. This is very from the ground up and basically assumes you
1816know nothing about the subject.
1817I am well aware you do know most of this stuff, but I want to be VERY sure that
1818you know them "correctly". Slight inaccuracies in definitions might slip through
1819daily conversations, but since we're doing proper gamedev together,
1820it's very crucial to be accurately-on the same page.
1821------------------------------ Terminology ------------------------------
1822---Art-related (useful to you directly):
1823Sprite: A static image used for an object.
1824 (each frame of an animation is also called a sprite)
1825Animation: Animations will be composed out of multiple (seperate) frames,
1826 Each frame would be composed of a single sprite (static image).
1827 The 'framerate' of it would not be saved in the art in anyway,
1828 Piskel has a preview (top-right) where you can adjust the speed to see how it looks,
1829 Just "tell" me the intended framerate once you're done.
1830
1831Skeletal animation: A form similar to the animation above, but augmented with code/logic,
1832 E.g. You'd draw each limb of a character separately (different sprite),
1833 And I'd use code/physics to animate movement. (see further reading)
1834
1835Skeletal art (not the proper term - I forget it): Useful for things such as equipment.
1836 E.g. The player, iron helmet, gold helmet, and multiple swords would each
1837 be seperate sprites. I'd 'overlay' them with code/logic. (see further reading)
1838
1839Resolution: This always refers to the size that you set the canvas to,
1840 NOT the exact/precise dimensions of what you draw in it!!!
1841 E.g A 32x32 canvas filled with a block of stone has a resolution of 32x32,
1842 A 32x32 canvas with a tiny stick drawn in the middle ALSO has a resolution 32x32.
1843 Note: "empty space around what you draw" is defined by 100% transparent pixels,
1844 What I'm trying to say is, please don't mistake white for transparent;
1845 A white pixel is very different from a transparent one.
1846
1847Transparency: How see-through something is, also known as alpha.
1848Opacity: How NOT-see-through something is.
1849
1850RGBA [Color systems]: Red, Green, Blue, Alpha.
1851 In the modern world (most commonly) each pixel is stored as 4 bytes
1852 (1 byte = 8 bits. 4 bytes = 4*8 = 32 bits.)
1853 (Each byte can represent any integer in the range [0-255], inclusive)
1854 (This results in 16,777,216 (~16M) different possible colors,
1855 if we count alpha, you'd get 4,294,967,296 (~4G))
1856
1857 Those are also often referred to as "the red channel", "alpha channel", etc...
1858
1859RGBA representation: A nibble is 4 bits (half a byte),
1860 A single hex digit ranges in [0-15], 4 bits have the same range.
1861 Hence, it's common to represent colors as 3 (4 with alpha) hex digits,
1862 Commonly prefixed with a hashtag. #AARRGGBB or #RRGGBB
1863 E.g. #0000FF -> Solid blue.
1864
1865Other color systems:
1866 HSB: Hue, Saturation, Brightness (Aka HSV, for value)
1867 CMY: Cyan, Magenta, Yellow.
1868 There are more...
1869 Internally, they work the same as RGB.
1870 They all also have alpha.
1871 They're mainly useful for artists, nothing technical.
1872 E.g in HSB you can move the B slider to make a color brighter,
1873 In RGB you'd have to move all 3 sliders an equal amount.
1874
1875Collision mask (Aka mask): Used by anything in the world that is also solid,
1876 Basically defines what the definition of two objects touching is.
1877 If the masks of two objects overlap, they are colliding.
1878
1879 Ideally, masks would always use precise-mapping,
1880 Aka every pixel (with non-zero alpha) in the sprite is collidable,
1881 Everything else is not.
1882 However this can be computationally-expensive for complex shapes,
1883 So often a simpler mask is used instead.
1884 E.g a complex shaped player humanoid would have a rectangular mask.
1885 (The smallest rectangle which still encompasses the whole player)
1886 (This could technically still have a lot of empty space (transparent pixels)
1887 which are being treated as collidable; sometimes it is made smaller so
1888 parts of the sprite might end up being not collidable)
1889 Either way, this is an imperfect best-we-can-do solution, but it's not nearly as
1890 bad as it sounds, you'll be shocked how common it actually is, and how much
1891 different sprites/masks are in most games you've played.
1892
1893 For our case, just assume that the engine will always use precise masks,
1894 And draw accordingly.
1895
1896 Reminder: Don't forget resolution = canvas size and is different from mask.
1897 A tiny torch in the middle of a 32x32 canvas has a small mask but a 32x32 resolution.
1898
1899
1900
1901---Non-art, but very general (still very useful to you):
1902"in the world": Things that exist in the game-world, aka map.
1903 Basically anything not in an inventory.
1904
1905Drawing: Drawing anything to the screen.
1906Rendering: Rendering stuff to the screen.
1907 Technically the above are similar, but rendering is for more
1908 computationally heavy-stuff, the explanation behind this is a topic for another day.
1909 I personally use rendering to refer to in-the-world stuff,
1910 And drawing for HUD's/GUI's/Menus (inventories, etc...)
1911
1912Item: Things that only exist inside inventories
1913 (aka only show up in GUI's, not in the world)
1914 E.g sticks, ingots, etc... (examples given in the context of my usual game design)
1915Block: (see below for further details) Everything, in the world,
1916 That is placed and locked to the tile grid.
1917
1918Item/Block: While items themselves only exist in inventories, many of them do have
1919 block "equivalents", and vice-versa.
1920 E.g. mining "a block of stone" would give "a stone block item",
1921 And Placing "a stone block item" would create "a block of stone."
1922
1923 What this means, on the technical side:
1924 Item/Block pairs still use completely different sprites for each;
1925 Their sprites are in no special way related - AT ALL.
1926 You don't even need to have them be the same size or anything.
1927
1928 On the art'sy side: You should probably make sure they LOOK related,
1929 Aka make the player go "Oh, that dropped from this block."
1930 And/or "Oh, that's the same block, but inside my pocket.".
1931
1932
1933
1934---Slightly more field-specific/technical, but still useful for you,
1935 since you're my gf, and I use those daily:
1936Entity: (see below for further details) Everything, in the world,
1937 That is free-form (NOt locked to the grid - can move around freely)
1938 E.g Arrow, player, zombie.
1939
1940Mob: A sub-category of entities; any living creature.
1941 E.g Player, zombie.
1942
1943NPC: A sub-category of mobs; non-player-character (every mob except the player(s))
1944 E.g Zombie.
1945
1946Hostile/Neutral/Passive/Ambient mobs: Sub-categories of mobs,
1947 categorized by their behavior towards the player.
1948 Hostile: Attack on sight. E.g. Zombies
1949 Neutral: Attack only if provoked E.g. Wolves
1950 (by attacking them, getting too close, what have you)
1951 Passive: Never attack. E.g. Sheep
1952 Ambient: Useless. E.g. Some bird which doesn't even drop
1953 (mostly decorative) Any items when killed.
1954
1955Menus vs GUIs: I know you know both terms,
1956 but in the context of games they are slightly altered:
1957 Menus: Game-menus, E.g. the main menu, world-select menu, options menu, etc...
1958 GUI: The interfaces that pop-up when you interact with something in the world,
1959 E.g. The player's inventory, some machine's GUI, etc...
1960 E.g. "The chest's GUI"
1961 (in-game GUI's for in-game stuff are rarely/never referred to as menus.)
1962 UI: Synonym for GUI. 0% different in 2020, was very different in the 20th century.
1963
1964HUD: Heads-Up Display, is drawn on the screen, you don't interact with it.
1965 E.g. your health-bar or number of coins you have, always shown in some corner.
1966
1967
1968------------------------------ Further Reading ------------------------------
1969Large-blocks:
1970Multiblocks:
1971Connected textures:
1972Random textures:
1973Perlin noise:
1974Procedurally generated textures
1975Procedurally generated art:
1976------------------------------ Long Version ------------------------------
1977
1978--- Technical requirements:
1979
1980There are 3 main "types" of "objects" you will be making sprites for
1981
1982
1983
1984
1985------------------------------ Short Version ------------------------------
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998--]]
1999
2000/////////////////Exiting file: artDocs.lua/////////////////
2001//--------------------------------------------------------------------------------------------------------
2002/////////////////Entering file: box2DMeterTestResults.lua/////////////////
2003--[[
2004
2005All the following tests were performed by executing each
2006method twice; once after setMeter(32),
2007 and once after setMeter(1).
2008The entire test was reloaded everytime the meterscale was changed.
2009
2010[b = body ; s = shape ; f = fixture ; p = love.physics]
2011
2012layout:
2013method(params) ; args -> res_32 ; res_1
2014
2015========================================
2016p.setMeter(ms)
2017p.getMeter() -> 64 ; 1
2018
2019========================================
2020p.newWorld(-3, 9.8)
2021world:getGravity() -> -3, 9.8000001907349 ; SAME
2022 Note: Changed ms to 3200 and ran. Method returned same
2023 results; but the simulation ran much slower/broken-like.
2024========================================
2025world:setGravity(-3, 9.8) -> Ran the same test as above.
2026 But calling setGravity after world creation. Same results as above.
2027========================================
2028
2029shape sizes
2030body position
2031a mix of both
2032
2033mass, density
2034friction, restitution
2035
2036s:getPoints ; b:getWorldPoints()
2037
2038b:getLinearVelocity ; b:setLinearVelocity
2039b:applyForce ; b:applyImpulse
2040
2041p:newWorld(xgravity, ygravity)
2042
2043========================================
2044Conclusions:
2045setMeter(ms) -> Used to allow you to use pixel coordinates in all of your game;
2046For positions (bodies, etc...), sizes (shapes, etc...),
2047And even forces (setGravity, applyForce, setLinearVelocity, etc...).
2048
2049Plan:
2050Since, in TechCove, I intend to use meters for everything.
2051I shall,
20521- setMeter(1)
20532- define the MS to use; use it only in:
2054 1- At the start of love.draw: love.graphics.scale(MS, MS)
2055
2056
2057
2058
2059 DEPRECATED
2060 2- Object creation code (pos/dims)
2061 3- Moving objects by setting their coords directly
2062 (Which would most likely never occur)
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087--]]
2088
2089/////////////////Exiting file: box2DMeterTestResults.lua/////////////////
2090//--------------------------------------------------------------------------------------------------------
2091/////////////////Entering file: Event.lua/////////////////
2092local class = require "libs.cruxclass"
2093
2094---Read-only util
2095local function xlock(self)
2096 local inv = {}
2097 for k, v in pairs(self) do
2098 inv[k] = v
2099 self[k] = nil
2100 end
2101
2102 local mt = getmetatable(self)
2103 local oopindex = mt.__index
2104 local function index(_, k)
2105 local o = inv[k]
2106 if o and k ~= "class" then return o end
2107 return oopindex(self, k)
2108 end
2109
2110 function self:iter()
2111 return function(_, k)
2112 local nk, v = next(inv, k)
2113 if nk == "class" then nk, v = next(inv, nk) end
2114 return nk, v
2115 end
2116 end
2117
2118 mt.__index = index
2119 mt.__newindex = function() error "All Event fields are read-only." end,
2120 setmetatable(self, mt)
2121end
2122
2123local function lock(self)
2124 local inv = {}
2125
2126 function self.iter()
2127 return function(_, k)
2128 local nk, v = next(self, k)
2129 if nk == "class" or nk == "iter" then
2130 nk, v = next(self, nk)
2131 end
2132 return nk, v
2133 end
2134 end
2135
2136 return setmetatable(inv, {
2137 __index = self,
2138 __newindex = function() error "All Event fields are read-only." end,
2139 __tostring = self.__tostring,
2140 })
2141end
2142
2143local Event = class("Event")
2144function Event:init()
2145end
2146
2147local new = Event.__new
2148function Event.static:__new(...)
2149 local inst = new(self, ...)
2150 return lock(inst)
2151end
2152
2153return Event
2154
2155--[[
2156local Event = require "evsys.Event"
2157
2158print(Event)
2159local e = Event(42)
2160
2161print(e)
2162print(e.k)
2163e:instanceMethod()
2164print(e.class)
2165print(e.super)
2166
2167print(e.iter)
2168--print(e:iter())
2169print ' --------- '
2170for k, v in pairs(e) do print(k, v) end c = next;
2171print ' --------- '
2172for k, v in e:iter() do print(k, v) end
2173
2174e.k = 3
2175print('k', e.k)
2176e.y = 3
2177--]]
2178
2179/////////////////Exiting file: Event.lua/////////////////
2180//--------------------------------------------------------------------------------------------------------
2181/////////////////Entering file: Evsys.lua/////////////////
2182local class = require "libs.cruxclass"
2183local Event = require "evsys.Event"
2184
2185--local Game = require "core.Game"
2186--local Registry = require "istats.Registry"
2187
2188local Evsys = class("Evsys")
2189function Evsys:init() --@Singletone
2190 self.evs = {}
2191 self.q = {}
2192end
2193
2194function Evsys:lockOn(class)
2195 self.lock = class
2196end
2197
2198function Evsys:attach(e, f)
2199 assert(e:subclassof(Event) or e == Event, "May only attach Event or a subclass of it.")
2200 assert(type(f) == 'function', "Callback must be a function.")
2201
2202 if not self.evs[e] then self.evs[e] = {} end --If first time attaching to Event e, create table for it.
2203 if not self.evs[e][self.lock] then --If first time attaching this class to said event, craete a table for it.
2204 self.evs[e][self.lock] = {f = {}, i = {}}
2205 end
2206 table.insert(self.evs[e][self.lock].f, f)
2207end
2208
2209function Evsys:subscribe(inst)
2210 for _, v in pairs(self.evs) do
2211 if v[inst.class] then
2212 table.insert(v[inst.class].i, inst)
2213 end
2214 end
2215end
2216
2217function Evsys:queue(e)
2218 assert(e.instanceof and e:instanceof(Event), "May only queue Event or a subclass of it.")
2219 table.insert(self.q, e)
2220end
2221
2222
2223local function fire(self, e)
2224 for _, class in pairs(self.evs[e.class] or {}) do
2225 for _, inst in pairs(class.i) do
2226 for _, f in pairs(class.f) do f(inst, e) end
2227 end
2228 end
2229end
2230
2231function Evsys:poll()
2232 while #self.q > 0 do
2233 fire(self, self.q[1])
2234 table.remove(self.q, 1)
2235 end
2236end
2237
2238return Evsys()
2239
2240
2241/////////////////Exiting file: Evsys.lua/////////////////
2242//--------------------------------------------------------------------------------------------------------
2243/////////////////Entering file: IEventHandler.lua/////////////////
2244local Mixins = require "libs.Mixins"
2245local Evsys = require "evsys.Evsys"
2246
2247local IEventHandler = Mixins("IEventHandler")
2248
2249---Setup
2250function IEventHandler:__included(class)
2251 Evsys:lockOn(class)
2252end
2253
2254Mixins.onPostInit(IEventHandler, function(self)
2255 if DEBUG.EVENT_SUBS then print(string.format("%s\t Subscribed to the evsys.", self)) end
2256 Evsys:subscribe(self)
2257end)
2258
2259---Methods
2260function IEventHandler:attach(e, f)
2261 if DEBUG.EVENT_ATTACHES then
2262 print(string.format("[%s] attached [%s] to [%s].", self, f, e.__name__))
2263 end
2264 Evsys:attach(e, f)
2265end
2266
2267return IEventHandler
2268
2269
2270
2271
2272/////////////////Exiting file: IEventHandler.lua/////////////////
2273//--------------------------------------------------------------------------------------------------------
2274/////////////////Entering file: KeypressedEvent.lua/////////////////
2275local class = require "libs.cruxclass"
2276local Event = require "evsys.Event"
2277
2278local KeypresedEvent = class("KeypresedEvent", Event)
2279function KeypresedEvent:init(k)
2280 self.k = k
2281end
2282
2283return KeypresedEvent
2284
2285
2286/////////////////Exiting file: KeypressedEvent.lua/////////////////
2287//--------------------------------------------------------------------------------------------------------
2288/////////////////Entering file: KeyboardEvent.lua/////////////////
2289local class = require "libs.cruxclass"
2290local Event = require "evsys.Event"
2291
2292local KeyboardEvent = class("KeyboardEvent", Event)
2293function KeyboardEvent:init(k, code, rpt, dir)
2294 Event.init(self)
2295 self.k, self.code, self.rpt, self.dir = k, code, rpt, dir
2296end
2297
2298KeyboardEvent.PRESS = 0
2299KeyboardEvent.RELEASE = 1
2300
2301return KeyboardEvent
2302
2303
2304/////////////////Exiting file: KeyboardEvent.lua/////////////////
2305//--------------------------------------------------------------------------------------------------------
2306/////////////////Entering file: KeypressEvent.lua/////////////////
2307local class = require "libs.cruxclass"
2308local KeyboardEvent = require "evsys.input.KeyboardEvent"
2309
2310local KeypressEvent = class("KeypressEvent", KeyboardEvent)
2311function KeypressEvent:init(k, code, rpt)
2312 KeyboardEvent.init(self, k, code, rpt,
2313 KeyboardEvent.PRESS)
2314end
2315
2316return KeypressEvent
2317
2318
2319/////////////////Exiting file: KeypressEvent.lua/////////////////
2320//--------------------------------------------------------------------------------------------------------
2321/////////////////Entering file: KeyreleaseEvent.lua/////////////////
2322local class = require "libs.cruxclass"
2323local KeyboardEvent = require "evsys.input.KeyboardEvent"
2324
2325local KeyreleaseEvent = class("KeyreleaseEvent", KeyboardEvent)
2326function KeyreleaseEvent:init(k, code, rpt)
2327 KeyboardEvent.init(self, k, code, rpt,
2328 KeyboardEvent.RELEASE)
2329end
2330
2331return KeyreleaseEvent
2332
2333
2334/////////////////Exiting file: KeyreleaseEvent.lua/////////////////
2335//--------------------------------------------------------------------------------------------------------
2336/////////////////Entering file: globals.lua/////////////////
2337--[[
2338
2339TODO: add all classes to a template similar to love's.
2340 Usage:
2341 local IHealth = act.beahvior.IHealth
2342 -- the rest is the same.
2343 Pros:
2344 - Far less keystrokes to include class.
2345 No require ""
2346 Auto-completion is available.
2347 - First-time requiring of all modules would always happen in a predictable order.
2348 Debate:
2349 Disallow direct usage of act.package.class?
2350 Allow it only for utils/libs?
2351 Allow it only in class-headers?
2352 local WorldObj = act.libs.class("WorldObj", act.template.Thing):include(act.behavior.IBoundingBox)
2353 local WorldObj = class("WorldObj", Thing):include(IBoundingBox)
2354 Allow it everywhere?
2355
2356TODO: do a proper logging system
2357TODO: move most highly-generic helper functions here
2358--]]
2359
2360utils = require "libs.misc"
2361utils.t = require "libs.tables"
2362
2363
2364
2365
2366
2367/////////////////Exiting file: globals.lua/////////////////
2368//--------------------------------------------------------------------------------------------------------
2369/////////////////Entering file: Filter.lua/////////////////
2370local class = require "libs.cruxclass"
2371
2372------------------------------ Helper Methods ------------------------------
2373local function formatArg(arg)
2374 local t = type(arg)
2375 if t == "table" or t == "nil" then return t
2376 else return {t} end
2377end
2378
2379------------------------------ Constructor ------------------------------
2380local Filter = class("Filter")
2381function Filter:init(items, sizes, tags, nItems, nSizes, nTags)
2382 self.items = formatArg(items) or Filter._DEFAULT_WHITE
2383 self.sizes = formatArg(sizes) or Filter._DEFAULT_WHITE
2384 self.tags = formatArg(tags) or Filter._DEFAULT_WHITE
2385
2386 self.nItems = formatArg(nItems) or Filter._DEFAULT_BLACK
2387 self.nSizes = formatArg(nSizes) or Filter._DEFAULT_BLACK
2388 self.nTags = formatArg(nTags) or Filter._DEFAULT_BLACK
2389end
2390
2391------------------------------ Constants ------------------------------
2392Filter.ALL = 0 --Must not equal any of Item.SIZES
2393Filter.NONE = -1 --Must not equal any of Item.SIZES
2394
2395Filter._DEFAULT_WHITE = Filter.ALL
2396Filter._DEFAULT_BLACK = Filter.NONE
2397
2398------------------------------ API ------------------------------
2399
2400------------------------------ Getters/Setters ------------------------------
2401
2402------------------------------ Factories ------------------------------
2403function Filter:fWhitelist(items, sizes, tags)
2404 return Filter(items, sizes, tags)
2405end
2406
2407function Filter:fBlacklist(nItems, nSizes, nTags)
2408 return Filter(nil, nil, nil, nItems, nSizes, nTags)
2409end
2410
2411function Filter:fItems(items, nItems)
2412 return Filter(items, nil, nil, nItems, nil, nil)
2413end
2414
2415function Filter:fSizes(sizes, nSizes)
2416 return Filter(nil, sizes, nil, nil, nSizes, nil)
2417end
2418
2419function Filter:fTags(tags, nTags)
2420 return Filter(nil, nil, tags, nil, nil, nTags)
2421end
2422
2423------------------------------ Utils ------------------------------
2424
2425------------------------------ Object-Common Methods ------------------------------
2426function Filter:clone()
2427 return Filter(self.items, self.sizes, self.tags,
2428 self.Nitems, self.Sizes, self.nTags)
2429end
2430
2431return Filter
2432
2433--[[
2434factories:
2435 fWhitelist(items, sizes, tags)
2436 fBlacklist(nItems, nSizes, nTags)
2437
2438 fItems(items, nItems)
2439 fSizes(sizes, nSizes)
2440 fTags(tags, nTags)
2441
2442origin - s1 = 32 ; s2 = 48
2443s2:add(s1) - s1 = 16 ; s2 = 64
2444
2445origin - s1 = 32 ; s2 = 48
2446s1 = s2:take() - s1 = 64 ; s2 = 16
2447
2448origin - s1 = 32 ; s2 = 48
2449s1 = s2:take(16) - s1 = 48 ; s2 = 32
2450
2451--]]
2452
2453
2454
2455
2456
2457/////////////////Exiting file: Filter.lua/////////////////
2458//--------------------------------------------------------------------------------------------------------
2459/////////////////Entering file: IContainable.lua/////////////////
2460local Mixins = require "libs.Mixins"
2461
2462------------------------------ Setup ------------------------------
2463local IContainable = Mixins("IContainable")
2464Mixins.onPostInit(IContainable, function(self)
2465 self:_onUpdate()
2466end)
2467
2468------------------------------ Callbacks ------------------------------
2469function IContainable:_onUpdate()
2470 if self.parent then self.parent:_onChildUpdate(self) end
2471end
2472
2473function IContainable:_onParentUpdate()
2474
2475end
2476
2477------------------------------ Getters/Setters ------------------------------
2478function IContainable:getParent() return self.parent end
2479function IContainable:_setParent(p)
2480 self.parent = p
2481end
2482
2483return IContainable
2484
2485
2486/////////////////Exiting file: IContainable.lua/////////////////
2487//--------------------------------------------------------------------------------------------------------
2488/////////////////Entering file: IContainer.lua/////////////////
2489local Mixins = require "libs.Mixins"
2490
2491------------------------------ Setup ------------------------------
2492local IContainer = Mixins("IContainer")
2493Mixins.onPostInit(IContainer, function(self)
2494 self:_onUpdate()
2495end)
2496
2497------------------------------ API ------------------------------
2498function IContainer:combine(...)
2499 self:_onUpdate()
2500end
2501
2502function IContainer:add(...)
2503 self:_onUpdate()
2504end
2505
2506function IContainer:sub(...)
2507 self:_onUpdate()
2508end
2509
2510------------------------------ Callbacks ------------------------------
2511function IContainer:_onUpdate()
2512 if self.parent then self.parent:_onChildUpdate(self) end
2513 if self.child then self.child:_onParentUpdate() end
2514end
2515
2516function IContainer:_onChildUpdate(child)
2517
2518end
2519
2520function IContainer:_onParentUpdate()
2521
2522end
2523
2524------------------------------ Getters/Setters ------------------------------
2525function IContainer:getParent() return self.parent end
2526function IContainer:_setParent(p)
2527 self.parent = p
2528end
2529
2530------------------------------ Child Getters/Setters ------------------------------
2531function IContainer:getChild() return self.child end
2532
2533function IContainer:_setChild(c)
2534 if self.child then self.child:_setParent(nil) end
2535 if c then c:_setParent(self) end
2536 self.child = c
2537end
2538
2539function IContainer:_removeChild()
2540 self:_setChild(nil)
2541end
2542
2543return IContainer
2544
2545
2546--[[
2547
2548
2549child / self / parent
2550
2551combine / add / sub
2552
2553emptiable
2554
2555get/set child/parent
2556
2557get/set content
2558
2559
2560
2561--]]
2562
2563--[[
2564local function cleanupArgs(from) end
2565local function combineItemStack(its, n) end
2566local function combineSlot(slot, n) end
2567local function combineInventory(inv, n) end
2568
2569
2570local function combine(from, n)
2571 return utils.ovld({from, n}, --args
2572 {cleanupArgs}, --optional cleanup function[1]
2573 combineItemStack, {ItemStack},
2574 combineSlot, {Slot},
2575 combineInventory, {Inventory}
2576 )
2577
2578
2579end
2580
2581
2582[1] The clean up function, if present, is used as follows:
2583{cleanup, nx, ny, ... } cleans up the provided args, for the function before it.
2584 If no numbers are provided, cleans up all args.
2585
2586 If applied after the initial args - cleans up all functions.
2587 A mixture of general and function-specific cleanup may be used.
2588
2589syntax:
2590utils.ovld({args} {allCleanupF, applyToArgN, ...},
2591 f1 {arg-types}, {f1CleanupF, applyToArgN, ...},
2592 f2 {arg-types}, {f2CleanupF, applyToArgN, ...},
2593 f3 {arg-types}, {f3CleanupF, applyToArgN, ...},
2594 ...
2595
2596Note: an empty arg-types tables is called if all args are nil.
2597Note: Arg-order is preserved, each arg is only checked against it's position in
2598 the provided overloads.
2599Note: allCleanupF is applied to all args before anything else is done.
2600
2601args types:
2602 string = s
2603 number = n
2604 function= f
2605 table = t
2606 nil = ni
2607 thread = th
2608 userdata= u
2609 class = Class
2610
2611 strict = -s
2612 minimal = -m
2613
2614
2615Notes:
2616 - Functions are checked in order, the first matching one is called.
2617 - By default once all args for a function are found, it is called,
2618 passed the founds args, followed by any 'more' arguments come after them.
2619 (common-args)
2620 - Minimal does the same as above but does not pass the function common-args.
2621 - Strict only calls a function if it's args match the base-args,
2622 aka if no common-args are present.
2623--]]
2624
2625
2626
2627/////////////////Exiting file: IContainer.lua/////////////////
2628//--------------------------------------------------------------------------------------------------------
2629/////////////////Entering file: IInventory.lua/////////////////
2630local class = require "libs.cruxclass"
2631
2632------------------------------ Helper Methods ------------------------------
2633
2634------------------------------ Constructor ------------------------------
2635local IInventory = class("IInventory")
2636function IInventory:init()
2637end
2638
2639------------------------------ Getters / Setters ------------------------------
2640
2641return IInventory
2642
2643/////////////////Exiting file: IInventory.lua/////////////////
2644//--------------------------------------------------------------------------------------------------------
2645/////////////////Entering file: IMultiContainer.lua/////////////////
2646local Mixins = require "libs.Mixins"
2647
2648------------------------------ Setup ------------------------------
2649local IMultiContainer = Mixins("IMultiContainer")
2650Mixins.onPostInit(IMultiContainer, function(self)
2651 self:_onUpdate()
2652end)
2653
2654------------------------------ API ------------------------------
2655function IMultiContainer:combine(...)
2656 self:_onUpdate()
2657end
2658
2659function IMultiContainer:add(...)
2660 self:_onUpdate()
2661end
2662
2663function IMultiContainer:sub(...)
2664 self:_onUpdate()
2665end
2666
2667------------------------------ Callbacks ------------------------------
2668function IMultiContainer:_onUpdate()
2669 if self.parent then self.parent:_onChildUpdate(self) end
2670 if self.children then
2671 self:applyOnChildren(function(k, v) v:_onParentUpdate() end)
2672 end
2673end
2674
2675function IMultiContainer:_onChildUpdate(child)
2676
2677end
2678
2679function IMultiContainer:_onParentUpdate()
2680
2681end
2682
2683------------------------------ Utils ------------------------------
2684function IMultiContainer:applyOnChildren(f)
2685 for k, v in ipairs(self.children) do
2686 local rtVal = f(k, v)
2687 if rtVal then return rtVal end
2688 end
2689end
2690
2691------------------------------ Getters/Setters ------------------------------
2692function IMultiContainer:getParent() return self.parent end
2693function IMultiContainer:_setParent(p)
2694 self.parent = p
2695end
2696
2697------------------------------ Child Getters/Setters ------------------------------
2698function IMultiContainer:getChildren() return self.children end
2699function IMultiContainer:getChild(i) return self.children[i] end
2700
2701function IMultiContainer:_setChildren(c)
2702 if c and not c[1].instanceof then c = {c} end
2703 self:applyOnChildren(function(k, v) v:_setParent(nil) end)
2704 self.children = c
2705 if c then self:applyOnChildren(function(k, v) v:_setParent(self) end) end
2706end
2707
2708function IMultiContainer:_setChild(i, c)
2709 if self.children[i] then self.children[i]:_setParent(nil) end
2710 if c then c:_setParent(self) end
2711 self.children[i] = c
2712end
2713
2714function IMultiContainer:_addChild(c)
2715 if c then
2716 c:_setParent(self)
2717 self.children[#self.children] = c
2718 end
2719end
2720
2721---Takes an index-to-use or child-to-find.
2722function IMultiContainer:_removeChild(c)
2723 if type(c) == 'number' then
2724 local child = table.remove(self.children, c)
2725 if child then
2726 child:_setParent(nil)
2727 return child
2728 end
2729 else --obj
2730 self:applyOnChildren(function(k, v)
2731 if v == c then
2732 local child = table.remove(self.children, k)
2733 child:_setParent(nil)
2734 return child
2735 end
2736 end)
2737 end
2738end
2739return IMultiContainer
2740
2741
2742--[[
2743
2744
2745child / self / parent
2746
2747combine / add / sub
2748
2749emptiable
2750
2751get/set child/parent
2752
2753get/set content
2754
2755
2756
2757--]]
2758
2759--[[
2760local function cleanupArgs(from) end
2761local function combineItemStack(its, n) end
2762local function combineSlot(slot, n) end
2763local function combineInventory(inv, n) end
2764
2765
2766local function combine(from, n)
2767 return utils.ovld({from, n}, --args
2768 {cleanupArgs}, --optional cleanup function[1]
2769 combineItemStack, {ItemStack},
2770 combineSlot, {Slot},
2771 combineInventory, {Inventory}
2772 )
2773
2774
2775end
2776
2777
2778[1] The clean up function, if present, is used as follows:
2779{cleanup, nx, ny, ... } cleans up the provided args, for the function before it.
2780 If no numbers are provided, cleans up all args.
2781
2782 If applied after the initial args - cleans up all functions.
2783 A mixture of general and function-specific cleanup may be used.
2784
2785syntax:
2786utils.ovld({args} {allCleanupF, applyToArgN, ...},
2787 f1 {arg-types}, {f1CleanupF, applyToArgN, ...},
2788 f2 {arg-types}, {f2CleanupF, applyToArgN, ...},
2789 f3 {arg-types}, {f3CleanupF, applyToArgN, ...},
2790 ...
2791
2792Note: an empty arg-types tables is called if all args are nil.
2793Note: Arg-order is preserved, each arg is only checked against it's position in
2794 the provided overloads.
2795Note: allCleanupF is applied to all args before anything else is done.
2796
2797args types:
2798 string = s
2799 number = n
2800 function= f
2801 table = t
2802 nil = ni
2803 thread = th
2804 userdata= u
2805 class = Class
2806
2807 strict = -s
2808 minimal = -m
2809
2810
2811Notes:
2812 - Functions are checked in order, the first matching one is called.
2813 - By default once all args for a function are found, it is called,
2814 passed the founds args, followed by any 'more' arguments come after them.
2815 (common-args)
2816 - Minimal does the same as above but does not pass the function common-args.
2817 - Strict only calls a function if it's args match the base-args,
2818 aka if no common-args are present.
2819--]]
2820
2821
2822
2823/////////////////Exiting file: IMultiContainer.lua/////////////////
2824//--------------------------------------------------------------------------------------------------------
2825/////////////////Entering file: ItemDrop.lua/////////////////
2826local class = require "libs.cruxclass"
2827local Entity = require "template.Entity"
2828
2829------------------------------ Helper Methods ------------------------------
2830
2831------------------------------ Constructor ------------------------------
2832local ItemDrop = class("ItemDrop", Entity)
2833function ItemDrop:init(id, x, y)
2834 Entity.init(self, id, x, y)
2835end
2836
2837------------------------------ Getters / Setters ------------------------------
2838
2839return ItemDrop
2840
2841/////////////////Exiting file: ItemDrop.lua/////////////////
2842//--------------------------------------------------------------------------------------------------------
2843/////////////////Entering file: ItemStack.lua/////////////////
2844local class = require "libs.cruxclass"
2845local Item = require "template.Item"
2846
2847local IContainer = require "inv.IContainer"
2848
2849------------------------------ Helper Methods ------------------------------
2850
2851------------------------------ Constructor ------------------------------
2852local ItemStack = class("ItemStack"):include(IContainer)
2853function ItemStack:init(item, amount, parent)
2854 self:_setChild(item)
2855 self.amount = amount or self.DEFAULT_AMOUNT
2856 self:_setParent(parent) --Slot, ItemDrop, or nil.
2857 self:_onUpdate()
2858end
2859
2860------------------------------ Constants ------------------------------
2861ItemStack.DEFAULT_AMOUNT = 1
2862
2863------------------------------ Access Methods ------------------------------
2864
2865function ItemStack:combine(its, n)
2866 if not self.item:equals(its:getItem()) then return 0 end
2867 return self:add(its:sub(n))
2868end
2869
2870function ItemStack:add(n)
2871 if n and n > 0 then
2872 self.amount = self.amount + n
2873 self:_onUpdate()
2874 return self.amount - n
2875 end
2876end
2877
2878function ItemStack:sub(n)
2879 n = self:_constrainToMin(n)
2880 self.amount = self.amount - n
2881 self:_onUpdate()
2882 return self.amount + n
2883end
2884
2885------------------------------ Internals ------------------------------
2886function ItemStack:_onUpdate()
2887 if self.item then self.mass = self.item:getMass() * self.amount end
2888 IContainer._onUpdate(self)
2889end
2890
2891function ItemStack:_onChildUpdate()
2892
2893end
2894
2895function ItemStack:_constrainToMin(n)
2896 return math.min(n or self.amount, self.amount)
2897end
2898------------------------------ Getters / Setters ------------------------------
2899function ItemStack:getItem() return self:getChild() end
2900function ItemStack:getAmount() return self.amount end
2901function ItemStack:getMass() return self.mass end
2902
2903function ItemStack:setItem(item)
2904 self:_setChild(item)
2905 self:_onUpdate()
2906end
2907function ItemStack:setAmount(a)
2908 self.amount = a
2909 self:_onUpdate()
2910end
2911
2912function ItemStack:setContents(i, amount) --Also takes an ItemStack
2913 if i:instanceof(ItemStack) then
2914 self:setItem(i:getItem():clone())
2915 self:setAmount(i:getAmount())
2916 elseif i:instanceof(Item) then
2917 self:setItem(i)
2918 self.item = i
2919 self:setAmount(amount or self.DEFAULT_AMOUNT)
2920 else error "Can only take either an ItemStack, or Item and amount(default = 1)." end
2921end
2922
2923------------------------------ Util-Getters (For Quick Access) ------------------------------
2924function ItemStack:getItemSize() return self.child:getSize() end
2925function ItemStack:getItemTags() return self.child:getTags() end
2926function ItemStack:cloneItem() return self.child:clone() end
2927------------------------------ Object-Common Methods ------------------------------
2928function ItemStack:clone()
2929 return ItemStack(self:cloneItem(), self.amount, self.parent)
2930end
2931
2932return ItemStack
2933
2934--[[
2935
2936add(its): Adds its to itself, if possible. Returns the added amount. (mutates it's arg)
2937take(n): Removes n from itself. Returns the removed amount.
2938
2939
2940Used for transferring between stacks.
2941 combine(its, n): If identical/possible, the caller(self) will take FROM the arg(its).
2942 If n = nil; takes as much as possible.
2943
2944Used for altering/modifying stacks:
2945I.e. Creating/Voiding items. E.g. crafting, trash cans, etc...
2946 add(n): Adds the given amount to the stack,
2947 If n = nil; add as much as possible (max out).
2948 Only up to <=maxStack. Returns the dif.
2949 sub(n): Subtracts the given amount from the stack.
2950 If n = nil; remove as much as possible (reduce to zero).
2951 Only down to >=0. Returns the dif.
2952
2953
2954
2955--]]
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966/////////////////Exiting file: ItemStack.lua/////////////////
2967//--------------------------------------------------------------------------------------------------------
2968/////////////////Entering file: Slot.lua/////////////////
2969local class = require "libs.cruxclass"
2970local Item = require "template.Item"
2971
2972local Filter = require "inv.Filter"
2973local ItemStack = require "inv.ItemStack"
2974local IContainer = require "inv.IContainer"
2975
2976------------------------------ Helper Methods ------------------------------
2977
2978------------------------------ Constructor ------------------------------
2979local Slot = class("Slot"):include(IContainer)
2980function Slot:init(inFilter, outFilter, itemStack, parent)
2981 self.inFilter = inFilter or Filter()
2982 self.outFilter = outFilter or Filter()
2983 self:_setChild(itemStack)
2984 self:_setParent(parent) --Inv, or nil.
2985end
2986
2987------------------------------ Access Methods ------------------------------
2988local function combineItemStack(its, n, self)
2989 if not self:mayCombine(its, n) then return 0 end
2990 if self.child then
2991 n = self:_constrainToMax(n)
2992 return self.child:combine(its, n)
2993 else
2994 local cap = self:getCapacity(its)
2995 local a = its:getAmount()
2996 n = its:_constrainToMin(n)
2997 if n == a and cap >= a then
2998 self:_setChild(its)
2999 return a
3000 else
3001 local dif = its:sub(n)
3002 self:_setChild( ItemStack(its:cloneItem(), dif) )
3003 return dif
3004 end
3005 end
3006end
3007
3008local function combineSlot(slot, n, self)
3009 if slot:mayBeCombined(self, n) then
3010 return combineItemStack(slot:getItemStack(), n, self)
3011 end
3012end
3013
3014function Slot:combine(from, n)
3015 return utils.ovld({from, n, self},
3016 combineItemStack, {ItemStack},
3017 combineSlot, {Slot}
3018 )
3019end
3020
3021function Slot:add(n)
3022 if self:mayAdd(n) then
3023 return self.child:add(n)
3024 end
3025end
3026
3027function Slot:sub(n)
3028 if self:maySub(n) then
3029 return self.child:sub(n)
3030 end
3031end
3032------------------------------ Callbacks ------------------------------
3033function Slot:_onChildUpdate()
3034 if self.child and self.child:getAmount() == 0 then
3035 self:_setChild(nil)
3036 end
3037end
3038
3039------------------------------ Direct Access Methods ------------------------------
3040
3041--function Slot:directAdd(n)
3042-- return self.itemStack:add(n)
3043--end
3044--
3045--function Slot:directSub(n)
3046-- return self.itemStack:sub(n)
3047--end
3048------------------------------ Filter-Related Methods ------------------------------
3049function Slot:mayCombine(from, n)
3050 return self.inFilter:check(from, n)
3051end
3052
3053
3054function Slot:mayBeCombined(into, n)
3055 return self.outFilter:check(into, n)
3056end
3057
3058function Slot:mayAdd(n)
3059 if self.child then
3060 return self.inFilter:check(self, n)
3061 else return false end
3062end
3063
3064function Slot:maySub(n)
3065 if self.child then
3066 return self.outFilter:check(self, n)
3067 else return false end
3068end
3069
3070------------------------------ Internals ------------------------------
3071function Slot:_constrainToMax(n)
3072 local cap = self:getCapacity()
3073 return math.min(n or cap, cap)
3074end
3075
3076function Slot:_constrainToMin(n)
3077 return math.min(n or self.amount, self.amount)
3078end
3079------------------------------ Getters / Setters ------------------------------
3080local function getCapItem(item) print('item') return item:getMaxStack() end
3081local function getCapItemStack(its) print('itemStack') return its.child:getMaxStack() end
3082local function getCap(self)
3083 print('self', self)
3084 return self.child and (self.child.child:getMaxStack() - self.child:getAmount())
3085end
3086
3087function Slot:getCapacity(source)
3088 return (utils.ovld({source, self},
3089 getCapItem, {Item},
3090 getCapItemStack, {ItemStack},
3091 getCap, {Slot}
3092 ))-- or 0
3093end
3094
3095function Slot:getInFilter() return self.inFilter end
3096function Slot:getOutFilter() return self.outFilter end
3097function Slot:getItemStack() return self:getChild() end
3098
3099function Slot:setInFilter(f) self.inFilter = f or Filter() end
3100function Slot:setOutFilter(f) self.outFilter = f or Filter() end
3101function Slot:setItemStack(its)
3102 self:_setChild(its)
3103end
3104
3105------------------------------ Util-Getters (For Quick Access) ------------------------------
3106
3107------------------------------ Object-Common Methods ------------------------------
3108function Slot:clone()
3109 return Slot(self.filter:clone(), self.its:clone(), self.parent)
3110end
3111
3112return Slot
3113
3114--[[
3115
3116function Slot:combine(from, n)
3117 local cap = self.its:getCapacity()
3118 if not self:mayAdd(from)then return 0 end
3119
3120 if from:instanceof(Slot) then
3121 local n = n or from:getItemStack():getAmount()
3122 local took = from:sub(math.min(cap, n))
3123 if took <= 0 then return 0 end
3124 return self.its:add(took)
3125 else
3126 local n = n or from:getAmount()
3127 local took = from:sub(math.min(cap, n))
3128 return self.its:add(took) end
3129end
3130
3131function Slot:combine(from, n)
3132 local from = self:mayCombine(from, n)
3133 if not from then return 0 end
3134
3135 n = n or self:getCapacity()
3136 if from:instanceof(Slot) then
3137 local took = from:directSub(n)
3138 self:directAdd
3139 else
3140
3141 end
3142end
3143
3144function Slot:add(n)
3145 if self:canAdd() then
3146 return self.its:add(its, n)
3147 end
3148end
3149
3150function Slot:take(n)
3151 if self.canTake(n) then
3152 local dif = self.its:take(n)
3153 if self.its.amount <= 0 then
3154 self.its:setParent(nil)
3155 self.its = nil
3156 end
3157 return dif
3158 end
3159end
3160
3161
3162--]]
3163
3164/////////////////Exiting file: Slot.lua/////////////////
3165//--------------------------------------------------------------------------------------------------------
3166/////////////////Entering file: Filter.lua/////////////////
3167local class = require "libs.cruxclass"
3168
3169------------------------------ Helper Methods ------------------------------
3170local function formatArg(arg)
3171 local t = type(arg)
3172 if t == "table" or t == "nil" then return t
3173 else return {t} end
3174end
3175
3176------------------------------ Constructor ------------------------------
3177local Filter = class("Filter")
3178function Filter:init(items, sizes, tags, nItems, nSizes, nTags)
3179 self.items = formatArg(items) or Filter._DEFAULT_WHITE
3180 self.sizes = formatArg(sizes) or Filter._DEFAULT_WHITE
3181 self.tags = formatArg(tags) or Filter._DEFAULT_WHITE
3182
3183 self.nItems = formatArg(nItems) or Filter._DEFAULT_BLACK
3184 self.nSizes = formatArg(nSizes) or Filter._DEFAULT_BLACK
3185 self.nTags = formatArg(nTags) or Filter._DEFAULT_BLACK
3186end
3187
3188------------------------------ Constants ------------------------------
3189Filter.ALL = 0 --Must not equal any of Item.SIZES
3190Filter.NONE = -1 --Must not equal any of Item.SIZES
3191
3192Filter._DEFAULT_WHITE = Filter.ALL
3193Filter._DEFAULT_BLACK = Filter.NONE
3194
3195------------------------------ API ------------------------------
3196
3197------------------------------ Getters/Setters ------------------------------
3198
3199------------------------------ Factories ------------------------------
3200function Filter:fWhitelist(items, sizes, tags)
3201 return Filter(items, sizes, tags)
3202end
3203
3204function Filter:fBlacklist(nItems, nSizes, nTags)
3205 return Filter(nil, nil, nil, nItems, nSizes, nTags)
3206end
3207
3208function Filter:fItems(items, nItems)
3209 return Filter(items, nil, nil, nItems, nil, nil)
3210end
3211
3212function Filter:fSizes(sizes, nSizes)
3213 return Filter(nil, sizes, nil, nil, nSizes, nil)
3214end
3215
3216function Filter:fTags(tags, nTags)
3217 return Filter(nil, nil, tags, nil, nil, nTags)
3218end
3219
3220------------------------------ Utils ------------------------------
3221
3222------------------------------ Object-Common Methods ------------------------------
3223function Filter:clone()
3224 return Filter(self.items, self.sizes, self.tags,
3225 self.Nitems, self.Sizes, self.nTags)
3226end
3227
3228return Filter
3229
3230--[[
3231factories:
3232 fWhitelist(items, sizes, tags)
3233 fBlacklist(nItems, nSizes, nTags)
3234
3235 fItems(items, nItems)
3236 fSizes(sizes, nSizes)
3237 fTags(tags, nTags)
3238
3239origin - s1 = 32 ; s2 = 48
3240s2:add(s1) - s1 = 16 ; s2 = 64
3241
3242origin - s1 = 32 ; s2 = 48
3243s1 = s2:take() - s1 = 64 ; s2 = 16
3244
3245origin - s1 = 32 ; s2 = 48
3246s1 = s2:take(16) - s1 = 48 ; s2 = 32
3247
3248--]]
3249
3250
3251
3252
3253
3254/////////////////Exiting file: Filter.lua/////////////////
3255//--------------------------------------------------------------------------------------------------------
3256/////////////////Entering file: IInventory.lua/////////////////
3257local class = require "libs.cruxclass"
3258
3259------------------------------ Helper Methods ------------------------------
3260
3261------------------------------ Constructor ------------------------------
3262local IInventory = class("IInventory")
3263function IInventory:init()
3264end
3265
3266------------------------------ Getters / Setters ------------------------------
3267
3268return IInventory
3269
3270/////////////////Exiting file: IInventory.lua/////////////////
3271//--------------------------------------------------------------------------------------------------------
3272/////////////////Entering file: ItemDrop.lua/////////////////
3273local class = require "libs.cruxclass"
3274local Entity = require "template.Entity"
3275
3276------------------------------ Helper Methods ------------------------------
3277
3278------------------------------ Constructor ------------------------------
3279local ItemDrop = class("ItemDrop", Entity)
3280function ItemDrop:init(id, x, y)
3281 Entity.init(self, id, x, y)
3282end
3283
3284------------------------------ Getters / Setters ------------------------------
3285
3286return ItemDrop
3287
3288/////////////////Exiting file: ItemDrop.lua/////////////////
3289//--------------------------------------------------------------------------------------------------------
3290/////////////////Entering file: ItemStack.lua/////////////////
3291local class = require "libs.cruxclass"
3292local Item = require "template.Item"
3293
3294------------------------------ Helper Methods ------------------------------
3295
3296------------------------------ Constructor ------------------------------
3297local ItemStack = class("ItemStack")
3298function ItemStack:init(item, amount, parent)
3299 self.item = item
3300 self.amount = amount or self.DEFAULT_AMOUNT
3301 self.parent = parent --Slot, ItemDrop, or nil.
3302
3303 if item then self.item:setParent(self) end
3304 self:_onUpdate()
3305end
3306
3307------------------------------ Constants ------------------------------
3308ItemStack.DEFAULT_AMOUNT = 1
3309
3310------------------------------ Access Methods ------------------------------
3311
3312function ItemStack:combine(its, n)
3313 if not self.item or self.item:equals(its:getItem()) then
3314 n = self:_constrainToMax()
3315 local dif = its:sub(n)
3316 if self.item then self:setItem(its.getItem())
3317 return self:add(its:sub(n))
3318 end
3319
3320 n = self:_constrainToMax()
3321 if not self.item then
3322 local item = its:getItem()
3323 local dif = its:sub(n)
3324 if dif > 0 then self:setItem(item); self:add(n) end
3325 return dif
3326 elseif self.item:equals(its:getItem()) then
3327 local dif = its:sub(n)
3328 if dif > 0 then self:add(n) end
3329 return dif
3330 end
3331end
3332
3333nil neq = itm and eq
3334nil eq = itm and neq
3335itm neq
3336itm eq
3337
3338
3339function ItemStack:add(n)
3340 if not self.item then return 0 end
3341 n = self:_constrainToMax(n)
3342 self.amount = self.amount + n
3343 self:_onUpdate()
3344 return self.amount - n
3345end
3346
3347function ItemStack:sub(n)
3348 if not self.item then return 0 end
3349 n = self:_constrainToMin(n)
3350 self.amount = self.amount - n
3351 self:_onUpdate()
3352 return self.amount + n
3353end
3354
3355------------------------------ Internals ------------------------------
3356function ItemStack:_onUpdate()
3357 if self.item then
3358 self.mass = self.item:getMass() * self.amount
3359 if self.amount == 0 then
3360 self.item:setParent(nil)
3361 self.item = nil
3362 end
3363 end
3364 if self.parent then self.parent:_onChildUpdate() end
3365end
3366
3367function ItemStack:_onChildUpdate()
3368
3369end
3370
3371function ItemStack:_constrainToMax(n)
3372 local cap = self:getCapacity()
3373 return math.min(n or cap, cap)
3374end
3375
3376function ItemStack:_constrainToMin(n)
3377 return math.min(n or self.amount, self.amount)
3378end
3379------------------------------ Getters / Setters ------------------------------
3380function ItemStack:getCapacity() return self.item:getMaxStack() - self.amount end
3381
3382function ItemStack:getItem() return self.item end
3383function ItemStack:getAmount() return self.amount end
3384function ItemStack:getMass() return self.mass end
3385function ItemStack:getParent() return self.parent end
3386
3387function ItemStack:setItem(itm)
3388 self.item:setParent(nil)
3389 self.item = itm
3390 self.item:setParent(self)
3391 self:_onUpdate()
3392end
3393function ItemStack:setAmount(a)
3394 self.amount = a
3395 self:_onUpdate()
3396end
3397function ItemStack:setParent(p)
3398 self.parent = p
3399 self.parent:_onChildUpdate()
3400end
3401
3402function ItemStack:setContents(i, amount) --Also takes an ItemStack
3403 if i:instanceof(ItemStack) then
3404 self:setItem(i:getItem():clone())
3405 self:setAmount(i:getAmount())
3406 elseif i:instanceof(Item) then
3407 self:setItem(i)
3408 self.item = i
3409 self.amount = amount or self.DEFAULT_AMOUNT
3410 else error "Can only take either an ItemStack, or Item and amount(default = 1)." end
3411 self:_onUpdate()
3412end
3413
3414------------------------------ Util-Getters (For Quick Access) ------------------------------
3415function ItemStack:getItemSize() return self.item:getSize() end
3416function ItemStack:getItemTags() return self.item:getTags() end
3417
3418------------------------------ Object-Common Methods ------------------------------
3419function ItemStack:clone()
3420 return ItemStack(self.item:clone(), self.amount, self.parent)
3421end
3422
3423return ItemStack
3424
3425--[[
3426
3427add(its): Adds its to itself, if possible. Returns the added amount. (mutates it's arg)
3428take(n): Removes n from itself. Returns the removed amount.
3429
3430
3431Used for transferring between stacks.
3432 combine(its, n): If identical/possible, the caller(self) will take FROM the arg(its).
3433 If n = nil; takes as much as possible.
3434
3435Used for altering/modifying stacks:
3436I.e. Creating/Voiding items. E.g. crafting, trash cans, etc...
3437 add(n): Adds the given amount to the stack,
3438 If n = nil; add as much as possible (max out).
3439 Only up to <=maxStack. Returns the dif.
3440 sub(n): Subtracts the given amount from the stack.
3441 If n = nil; remove as much as possible (reduce to zero).
3442 Only down to >=0. Returns the dif.
3443
3444
3445
3446--]]
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457/////////////////Exiting file: ItemStack.lua/////////////////
3458//--------------------------------------------------------------------------------------------------------
3459/////////////////Entering file: Slot.lua/////////////////
3460local class = require "libs.cruxclass"
3461local Filter = require "inv.Filter"
3462local ItemStack = require "inv.ItemStack"
3463
3464------------------------------ Helper Methods ------------------------------
3465
3466------------------------------ Constructor ------------------------------
3467local Slot = class("Slot")
3468function Slot:init(inFilter, outFilter, itemStack, parent)
3469 self.inFilter = inFilter or Filter()
3470 self.outFilter = outFilter or Filter()
3471 self.its = itemStack or ItemStack()
3472 itemStack:setParent(self)
3473 self.parent = parent --Inv, or nil.
3474end
3475
3476------------------------------ Access Methods ------------------------------
3477function Slot:combine(from, n)
3478 if self:mayCombine(from, n) then
3479 if from:instanceof(Slot) and from:mayBeCombined(self, n) then
3480 return self.itemStack:combine(from:getItemStack(), n)
3481 else return self.itemStack:combine(from, n) end
3482 end
3483end
3484
3485function Slot:add(n)
3486 if self:mayAdd(n) then
3487 return self.itemStack:add(n)
3488 end
3489end
3490
3491function Slot:sub(n)
3492 if self:maySub(n) then
3493 return self.itemStack:sub(n)
3494 end
3495end
3496------------------------------ Direct Access Methods ------------------------------
3497
3498--function Slot:directAdd(n)
3499-- return self.itemStack:add(n)
3500--end
3501--
3502--function Slot:directSub(n)
3503-- return self.itemStack:sub(n)
3504--end
3505------------------------------ Filter-Related Methods ------------------------------
3506function Slot:mayCombine(from, n)
3507 return self.inFilter:check(from, n)
3508end
3509
3510function Slot:mayAdd(n)
3511 return self.inFilter:check(self, n)
3512end
3513
3514function Slot:maySub(n)
3515 return self.outFilter:check(self, n)
3516end
3517
3518------------------------------ Internals ------------------------------
3519function Slot:_onUpdate()
3520
3521end
3522
3523
3524function Slot:_onChildUpdate()
3525
3526end
3527
3528function Slot:_constrainToMax(n)
3529 local cap = self:getCapacity()
3530 return math.min(n or cap, cap)
3531end
3532
3533function Slot:_constrainToMin(n)
3534 return math.min(n or self.amount, self.amount)
3535end
3536------------------------------ Getters / Setters ------------------------------
3537function Slot:getinFilter() return self.inFilter end
3538function Slot:getoutFilter() return self.outFilter end
3539function Slot:getItemSack() return self.itemStack end
3540function Slot:getParent() return self.parent end
3541
3542function Slot:setinFilter(f) self.inFilter = f or Filter() end
3543function Slot:setoutFilter(f) self.outFilter = f or Filter() end
3544function Slot:setItemStack(its)
3545 self.itemStack:setParent(nil)
3546 self.itemStack = its
3547 self.itemStack:setParent(self)
3548 self:_onUpdte()
3549end
3550function Slot:setParent(p)
3551 self.parent = p
3552 self.parent:_onChildUpdate()
3553end
3554
3555------------------------------ Object-Common Methods ------------------------------
3556function Slot:clone()
3557 return Slot(self.filter:clone(), self.its:clone(), self.parent)
3558end
3559
3560return Slot
3561
3562--[[
3563
3564function Slot:combine(from, n)
3565 local cap = self.its:getCapacity()
3566 if not self:mayAdd(from)then return 0 end
3567
3568 if from:instanceof(Slot) then
3569 local n = n or from:getItemStack():getAmount()
3570 local took = from:sub(math.min(cap, n))
3571 if took <= 0 then return 0 end
3572 return self.its:add(took)
3573 else
3574 local n = n or from:getAmount()
3575 local took = from:sub(math.min(cap, n))
3576 return self.its:add(took) end
3577end
3578
3579function Slot:combine(from, n)
3580 local from = self:mayCombine(from, n)
3581 if not from then return 0 end
3582
3583 n = n or self:getCapacity()
3584 if from:instanceof(Slot) then
3585 local took = from:directSub(n)
3586 self:directAdd
3587 else
3588
3589 end
3590end
3591
3592function Slot:add(n)
3593 if self:canAdd() then
3594 return self.its:add(its, n)
3595 end
3596end
3597
3598function Slot:take(n)
3599 if self.canTake(n) then
3600 local dif = self.its:take(n)
3601 if self.its.amount <= 0 then
3602 self.its:setParent(nil)
3603 self.its = nil
3604 end
3605 return dif
3606 end
3607end
3608
3609
3610--]]
3611
3612/////////////////Exiting file: Slot.lua/////////////////
3613//--------------------------------------------------------------------------------------------------------
3614/////////////////Entering file: Registry.lua/////////////////
3615local class = require "libs.cruxclass"
3616
3617local FilepathUtils = require "utils.FilepathUtils"
3618
3619local EShapes = require "behavior.EShapes"
3620local IBoundingBox = require "behavior.IBoundingBox"
3621local WeaponDef = require "template.WeaponDef"
3622--local Item = require "template.Item"
3623
3624--local Game = require "core.Game"
3625
3626------------------------------ Constructor ------------------------------
3627local Registry = class("Registry")
3628function Registry:init()
3629 error "Attempting to initialize static class."
3630end
3631
3632------------------------------ Data Env ------------------------------
3633local function data(d)
3634 local t = Registry.static.data
3635 local id = d[1]
3636 t[id] = t[id] or {}
3637
3638 for k, v in pairs(d) do
3639 if k ~= 1 then t[id][k] = v end
3640 end
3641end
3642
3643local mtFuncHolder = { --Same as the above, but only for __f / __d.
3644 __index = function(t, k)
3645 assert(k == "__f" or k == "__d", "Only __f or __d are auto-created. Attempted to index " .. k)
3646 t[k] = {}
3647 return t[k]
3648 end
3649}
3650local mtDefaultsHolder = { --If the user attempts to index r.className
3651 __index = function(t, k) --without initializing it, initialize it implicitly.
3652 if k == "idv" or k == "instv" then return end
3653 local idv = setmetatable({}, mtFuncHolder)
3654 local instv = setmetatable({}, mtFuncHolder)
3655 t[k] = setmetatable({idv = idv, instv = instv}, mtFuncHolder)
3656 return t[k]
3657 end
3658}
3659
3660local tempDefaultsHolder = setmetatable({}, mtDefaultsHolder)
3661
3662local dslEnv = {
3663 print = print, pairs = pairs, ipairs = ipairs,
3664 string = string, table = table, os = os,
3665 tostring = tostring, tonumber = tonumber,
3666 assert = assert, error = error,
3667
3668 data = data,
3669 r = tempDefaultsHolder,
3670
3671 WeaponDef = WeaponDef,
3672 EShapes = EShapes,
3673 IBoundingBox = IBoundingBox,
3674 masks = IBoundingBox.masks,
3675 Item = Item,
3676}
3677
3678------------------------------ Data Methods ------------------------------
3679local function loadFile(file, env)
3680 local f = love.filesystem.load(file)
3681 setfenv(f, env)
3682 f()
3683end
3684
3685local function loadDir(dir, env)
3686 local files = love.filesystem.getDirectoryItems(dir)
3687
3688 for k, v in ipairs(files) do
3689 local file = dir .. v
3690 if DEBUG.DATAPACK_LOAD then print('\t' .. file) end
3691 local type = love.filesystem.getInfo(file).type
3692 if type == 'directory' then loadDir(file .. '/', env)
3693 elseif type == 'file' then loadFile(file, env) end
3694 end
3695end
3696
3697local function loadAll(defaultsEnv, dataEnv)
3698 print("Loading defaults.")
3699 loadDir(FilepathUtils.love.path.istatsDefaults, defaultsEnv)
3700 if DEBUG.DATAPACK_CONTENTS then utils.t.print("defaults", defaultsEnv.r) end
3701
3702 print("Loading data.")
3703 loadDir(FilepathUtils.love.path.istatsData, dataEnv)
3704 if DEBUG.DATAPACK_CONTENTS then utils.t.print("data", Registry.data) end
3705
3706 print("Done loading datapack.")
3707 print()
3708end
3709
3710------------------------------ Data Loading ------------------------------
3711do
3712 Registry.data = {}
3713
3714 loadAll(dslEnv, dslEnv)
3715-- Registry.defaults = tempDefaultsHolder
3716 Registry.defaults = dslEnv.r
3717
3718-- local dat, def = Registry.data, Registry.defaults
3719-- local dat, def = Registry.data, tempDefaultsHolder
3720-- print(" --- r ---")
3721-- for k, v in pairs(dslEnv.r.Thing.idv or {}) do
3722-- print(k, v)
3723-- end
3724-- print()
3725--
3726-- print(" --- REG ---")
3727-- for k, v in pairs(def.Thing.idv or {}) do
3728-- print(k, v)
3729-- end
3730-- print()
3731-- print(" --- data ---")
3732-- for k, v in pairs(dat) do
3733-- print(k, v)
3734-- end
3735-- print()
3736--
3737-- for name, t in pairs(def) do
3738--
3739-- print(" --- " .. name .. ".idv ---")
3740-- for k, v in pairs(t.idv or {}) do
3741-- print(k, v)
3742-- end
3743-- print()
3744--
3745--
3746-- print(" --- " .. name .. ".instv ---")
3747-- for k, v in pairs(t.instv or {}) do
3748-- print(k, v)
3749-- end
3750-- print()
3751-- end
3752end
3753
3754------------------------------ Util Methods------------------------------
3755local function getterStr(str)
3756 return "get" .. (str:gsub("^%l", string.upper))
3757end
3758
3759local function appendTable(t1, t2)
3760 for _, v in ipairs(t2) do
3761 table.insert(t1, v)
3762 end
3763end
3764
3765------------------------------ Hierarchy Methods ------------------------------
3766local function fetchDirectHierarchy(class)
3767 local h = {class.__name__}
3768 if DEBUG.REG_APPLY then print("class.__name__", class.__name__) end
3769 for k, v in ipairs(class.__mixins__) do
3770 if DEBUG.REG_APPLY then print("\tmixins.__name__", v.__name__) end
3771 table.insert(h, v.__name__)
3772 end
3773 return h
3774end
3775
3776local function fetchHierarchy(inst)
3777 local class = inst.class
3778 local h = fetchDirectHierarchy(class)
3779 repeat
3780 local super = class.super
3781 if super then
3782 appendTable(h, fetchDirectHierarchy(super))
3783 end
3784 class = super
3785 until not class
3786 return h
3787end
3788
3789
3790
3791
3792------------------------------ Apply Stats Steps ------------------------------
3793local function getterFunc(id, inst, var, defs, default, dat, datum)
3794 if var == "__f" or var == "__d" then return nil end
3795 local f, d = defs.__f[var], defs.__d[var]
3796 local un = unpack
3797 local args = {id, inst, var, defs, default, dat, datum}
3798 if f and d then
3799 return function() return (datum and d(un(args))) or f(un(args)) end
3800 elseif f then
3801 return function() return datum or f(un(args)) end
3802 elseif d then
3803 return function() return (datum and d(un(args))) or default end
3804 else
3805 return function() return datum or default end
3806 end
3807end
3808--[[
3809cases: (for idv)
3810 f + d
3811 return (data and d(data)) or f()
3812 f
3813 return data or f()
3814 d
3815 return (data and d(data)) or default
3816 0
3817 return data or default
3818--]]
3819
3820local function handleIdvs(id, inst, h)
3821 local dat = Registry.data
3822 for _, name in ipairs(h) do
3823 local defs = Registry.defaults[name].idv or {}
3824 for var, default in pairs(defs) do
3825 local fstr = getterStr(var)
3826 local idDat = dat[id] or {}
3827 local datum = idDat[var]
3828 inst[fstr] = getterFunc(id, inst, var, defs, default, idDat, datum)
3829 end
3830 end
3831end
3832
3833local function handleInstvs(id, inst, h)
3834 local dat = Registry.data
3835 for _, name in ipairs(h) do
3836 local defs = Registry.defaults[name].instv or {}
3837 for var, default in pairs(defs) do
3838 local datum = dat[id] and dat[id][var]
3839 local f = getterFunc(id, inst, var, defs, default, dat[id], datum)
3840 inst[var] = f and f()
3841 end
3842 end
3843end
3844
3845------------------------------ Apply Stats ------------------------------
3846function Registry:apply(id, inst)
3847 local h = fetchHierarchy(inst)
3848-- for k, v in ipairs(h) do print(k, v) end
3849 handleIdvs(id, inst, h)
3850 handleInstvs(id, inst, h)
3851end
3852
3853--_G.Registry = Registry
3854--local Zombie = require "template.Zombie"
3855--Zombie(0, 0)
3856
3857return Registry
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888/////////////////Exiting file: Registry.lua/////////////////
3889//--------------------------------------------------------------------------------------------------------
3890/////////////////Entering file: generic.lua/////////////////
3891------------------------------ Blocks ------------------------------
3892data{"logOak",
3893 name = "Oak Log",
3894 desc = "Log(0)"
3895}
3896
3897data{"plankOak",
3898 name = "Oak Plank",
3899 desc = "Depressed Logs."
3900}
3901
3902data{"stickWood",
3903 name = "Wooden Stick",
3904 desc = "*pokes it with a stick*"
3905}
3906
3907------------------------------ Mobs ------------------------------
3908data{"mobZombie",
3909 name = "Undead",
3910 desc = "Zombie",
3911
3912 speed = 1.5,
3913 totalJumps = 1,
3914 maxHealth = 50,
3915
3916 w = 0.8,
3917 h = 1.1,
3918 mass = 1,
3919 friction = 0,
3920 category = masks.HOSTILE_MOB,
3921 mask = masks.NPC + masks.ITEM_DROP,
3922} -- 0011 1000 0000 0001
3923
3924data{"player",
3925 speed = 3,
3926 totalJumps = 3,
3927
3928 w = 0.6,
3929 h = 1,
3930 mass = 1,
3931 friction = 0,
3932
3933 category = masks.PLAYER,
3934 mask = masks.PLAYER + masks.PLAYER_PRJ,
3935}
3936
3937------------------------------ Weapons ------------------------------
3938data{"swordStone",
3939 maxDurability = 50,
3940 cooldown = 2,
3941 damage = 5,
3942}
3943
3944data{"swordIron",
3945 maxDurability = 250,
3946 cooldown = 2,
3947 damage = 15,
3948}
3949
3950data{"spearStone",
3951 maxDurability = 50,
3952 cooldown = 2,
3953 damage = 5,
3954 hitbox = {
3955 {
3956 anchor = WeaponDef.NATURAL,
3957-- transition = WeaponDef.INSTANT, --- skipped for last phase
3958 dur = 15,
3959 area = {0, 0, 0.1, 2},
3960 },
3961 },
3962}
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984/////////////////Exiting file: generic.lua/////////////////
3985//--------------------------------------------------------------------------------------------------------
3986/////////////////Entering file: inside.lua/////////////////
3987
3988
3989/////////////////Exiting file: inside.lua/////////////////
3990//--------------------------------------------------------------------------------------------------------
3991/////////////////Entering file: IBoundingBox.lua/////////////////
3992------------------------------ Physics Vars ------------------------------
3993local m = IBoundingBox.masks
3994t = r.IBoundingBox.idv
3995t.classCategories = {}
3996t.classMasks = {}
3997
3998
3999t.bodyDensity = 1
4000t.bodyMass = 1 --As to use Box2D's internal mass computation.
4001t.bodyFriction = 0
4002t.bodyRestitution = 0
4003t.shapeType = IBoundingBox.RECT
4004t.shapeA = 1
4005t.shapeB = 1
4006
4007function t.__f.shapeA(id, inst, var, defs, default, dat)
4008 return (dat and (dat.r or dat.w)) or default
4009end
4010function t.__f.shapeB(id, inst, var, defs, default, dat)
4011 return dat and dat.h or default
4012end
4013
4014--[[
4015
4016if dat[r] then return it
4017if dat[w] then return it
4018else return default
4019
4020--]]
4021
4022------------------------------ Categories ------------------------------
4023local c = t.classCategories --self:setCategory(c)
4024
4025c.unassigned = m.MP
4026
4027c.Block = m.BLOCK
4028c.ItemDrop = m.ITEM_DROP
4029
4030------------------------------ Masks ------------------------------
4031local k = t.classMasks --self:setMask(m.SOLID - k)
4032
4033k.unassigned = 0
4034
4035k.ItemDrop = m.PRJ + m.NPC
4036k.Npc = m.NPC + m.ITEM_DROP
4037
4038
4039t.category = 0
4040t.mask = 0
4041
4042function t.__f.category(id, inst, var, defs, default, dat)
4043 local cat = c[inst.class.__name__] --class default, if any
4044 return cat or c.unassigned
4045end
4046
4047function t.__f.mask(id, inst, var, defs, default, dat)
4048 local mask = k[inst.class.__name__] --class default, if any
4049 return m.SOLID - (mask or k.unassigned)
4050end
4051
4052function t.__d.mask(id, inst, var, defs, default, dat, datum)
4053 return m.SOLID - datum
4054end
4055
4056
4057
4058
4059
4060/////////////////Exiting file: IBoundingBox.lua/////////////////
4061//--------------------------------------------------------------------------------------------------------
4062/////////////////Entering file: general.lua/////////////////
4063
4064
4065------------------------------ Thing ------------------------------
4066t = r.Thing.idv
4067
4068t.name = "Unnamed"
4069t.desc = "Missing desc."
4070
4071function t.__f.name(id, inst, var, defs, default, dat)
4072 return '$' .. id
4073end
4074------------------------------ Rendering ------------------------------
4075
4076--t.spr = nil
4077
4078------------------------------ Item ------------------------------
4079t = r.Item.idv
4080
4081t.maxStack = 64
4082
4083t.mass = 1
4084--t.size = Item.SMALL
4085t.tags = {}
4086
4087/////////////////Exiting file: general.lua/////////////////
4088//--------------------------------------------------------------------------------------------------------
4089/////////////////Entering file: mobRelated.lua/////////////////
4090
4091------------------------------ IHealth ------------------------------
4092t = r.IHealth.instv
4093t.maxHealth = 100
4094
4095------------------------------ Mob ------------------------------
4096t = r.Mob.instv
4097
4098t.speed = 3
4099t.acceleration = 0.25
4100t.deacceleration = 0.9
4101
4102t.totalJumps = 1
4103t.jumpHeight = 1.5
4104t.jumpVelocityMult = 2
4105
4106------------------------------ MeleeWeapon ------------------------------
4107t = r.MeleeWeapon.instv
4108
4109--TODO: Upgrade melee-weapon phases to allow altering of all stats not just hitbox.
4110t.maxDurability = 100
4111t.cooldown = 5
4112
4113--TODO: Move hit-related stats to sub-table.
4114t.damage = 10
4115t.effects = {}
4116t.reHit = 0
4117t.hitbox = {
4118 start = {0, 0, 0, 0.2},
4119 startAnchor = WeaponDef.anchors.NATURAL,
4120 {
4121 anchor = WeaponDef.anchors.NATURAL,
4122 transition = WeaponDef.transitions.LINEAR_GROW,
4123 dur = 0.1,
4124 area = {0, 0, 1.5, 0.2},
4125 }, {
4126 anchor = WeaponDef.anchors.NATURAL,
4127 transition = WeaponDef.transitions.LINEAR_GROW,
4128-- transition = WeaponDef.transitions.INSTANT,
4129 dur = 0.5,
4130 area = {0, 0, 0, 0.2},
4131 },
4132-- {
4133-- anchor = WeaponDef.anchors.NATURAL,
4134-- transition = WeaponDef.transitions.LINEAR_GROW,
4135-- dur = 2,
4136---- freq = 0.5, --freq defaults to -1 (every tick)
4137-- area = {0, 0, 0, 0.8},
4138-- },
4139}
4140
4141
4142/////////////////Exiting file: mobRelated.lua/////////////////
4143//--------------------------------------------------------------------------------------------------------
4144/////////////////Entering file: idVars.lua/////////////////
4145local EShapes = require "behavior.EShapes"
4146
4147local t = {}
4148
4149------------------------------ Thing ------------------------------
4150t.NAME = "Unnamed"
4151t.DESC = "Missing desc."
4152
4153------------------------------ Rendering ------------------------------
4154t.SPR = nil
4155
4156------------------------------ IBoundingBox ------------------------------
4157t.BODY_DENSITY = nil
4158t.BODY_MASS = nil --As to use Box2D's internal mass computation.
4159t.BODY_FRICTION = nil
4160t.BODY_RESTITUTION = nil
4161t.SHAPE_TYPE = EShapes.RECT
4162t.SHAPE_A = 1
4163t.SHAPE_B = 1
4164
4165------------------------------ IHealth ------------------------------
4166t.MAX_HEALTH = 100
4167
4168return t
4169
4170
4171/////////////////Exiting file: idVars.lua/////////////////
4172//--------------------------------------------------------------------------------------------------------
4173/////////////////Entering file: masks.lua/////////////////
4174local IBoundingBox = require "FIX THE REGISTRY"
4175
4176local m = IBoundingBox.masks
4177local t = {}
4178t.categories = {}
4179t.masks = {}
4180------------------------------ Categories ------------------------------
4181local c = t.categories --self:setCategory(c)
4182
4183c.unassigned = m.MP
4184
4185c.Block = m.BLOCK
4186c.ItemDrop = m.ITEM_DROP
4187c.Player = m.PLAYER
4188
4189--TODO: remove after cleaning up Registry.
4190c.Zombie = m.HOSTILE_MOB
4191------------------------------ Masks ------------------------------
4192local k = t.masks --self:setMask(m.SOLID - k)
4193
4194k.unassigned = 0
4195
4196k.ItemDrop = m.PRJ + m.NPC
4197k.Player = m.PLAYER + m.PLAYER_PRJ
4198k.Npc = m.NPC + m.ITEM_DROP
4199
4200--TODO: remove after cleaning up Registry.
4201k.Zombie = m.NPC + m.ITEM_DROP
4202
4203--[[
4204Full hierarchy:
4205-Cats:
4206
4207c.WorldObj = m.MP
4208 c.Block = m.BLOCK
4209
4210 c.Entity = m.MP
4211 c.ItemDrop = m.ITEM_DROP
4212 c.Projectile = m.MP
4213 --No template classes for them; tagged upon construction from Projectile.
4214 c.PlayerPrj = m.PLAYER_PRJ
4215 c.NpcPrj = m.NPC_PRJ
4216 c.Mob = m.MP
4217 c.Player = m.PLAYER
4218 c.Npc = m.MP
4219
4220-------------------------------------------------------------------------------------
4221
4222-Masks:
4223
4224k.WorldObj = 0
4225 k.Block = 0
4226
4227 k.Entity = 0
4228 k.ItemDrop = m.PRJ + m.PLAYER
4229 k.Projectile = 0
4230 k.Mob = 0
4231 k.Player = m.PLAYER + m.PLAYER_PRJ
4232 k.Npc = m.NPC + m.ItemDrop
4233--]]
4234
4235return t
4236
4237
4238--[[
4239Example:
42400111 solid
42410010 prj
42420100 mob
4243
42440111 solid
42450110 prj + mob
4246
42470001 solid - (prj + mob)
4248
42490111 solid
42500010 mob
42510100 player
4252
4253
4254--]]
4255
4256/////////////////Exiting file: masks.lua/////////////////
4257//--------------------------------------------------------------------------------------------------------
4258/////////////////Entering file: instanceVars.lua/////////////////
4259local WeaponDef = require "template.WeaponDef"
4260
4261local t = {}
4262
4263------------------------------ IWalk, IJump ------------------------------
4264t.movement = {
4265 speed = 3,
4266 acceleration = 0.25,
4267 deacceleration = 0.9,
4268}
4269t.jumping = {
4270 totalJumps = 1,
4271 jumpHeight = 1.5,
4272 jumpVelocityMult = 2,
4273}
4274
4275------------------------------ MeleeWeapon ------------------------------
4276t.meleeWeapon = {
4277 --TODO: Upgrade melee-weapon phases to allow altering of all stats not just hitbox.
4278 maxDurability = 100,
4279 cooldown = 5,
4280
4281 --TODO: Move hit-related stats to sub-table.
4282 damage = 10,
4283 effects = {},
4284 reHit = 0,
4285 hitbox = {
4286 start = {0, 0, 0, 0.2},
4287 startAnchor = WeaponDef.anchors.NATURAL,
4288 {
4289 anchor = WeaponDef.anchors.NATURAL,
4290 transition = WeaponDef.transitions.LINEAR_GROW,
4291 dur = 0.1,
4292 area = {0, 0, 1.5, 0.2},
4293 }, {
4294 anchor = WeaponDef.anchors.NATURAL,
4295 transition = WeaponDef.transitions.LINEAR_GROW,
4296-- transition = WeaponDef.transitions.INSTANT,
4297 dur = 0.5,
4298 area = {0, 0, 0, 0.2},
4299 },
4300-- {
4301-- anchor = WeaponDef.anchors.NATURAL,
4302-- transition = WeaponDef.transitions.LINEAR_GROW,
4303-- dur = 2,
4304---- freq = 0.5, --freq defaults to -1 (every tick)
4305-- area = {0, 0, 0, 0.8},
4306-- },
4307 },
4308}
4309
4310return t
4311
4312/////////////////Exiting file: instanceVars.lua/////////////////
4313//--------------------------------------------------------------------------------------------------------
4314/////////////////Entering file: Enum.lua/////////////////
4315local function splitStr(s)
4316 local strs = {}
4317
4318 local iter = s:gmatch("[^%s]+") -- iter that splits on spaces
4319 for str in iter do
4320 table.insert(strs, str) -- insert all strs into an array
4321 end
4322
4323 local keys, t = {}, {}
4324 for _, v in ipairs(strs) do
4325 if not keys[v] then -- check strs for duplicate keys
4326 t[#t+1] = v
4327 keys[v] = true
4328 else error("Enum declared with duplicate identifiers!\nEnum:\t{" .. s .. "}") end
4329 end
4330
4331 return t
4332end
4333
4334------------------------------------------------------------------------------
4335local function Enum(s, light)
4336 local t, enums, strs = {}, {}, {}
4337
4338 strs = splitStr(s) -- split the constructor string in an array
4339
4340 local i = 1
4341 for _, str in ipairs(strs) do
4342 if not light then
4343 enums[str .. "__string"] = str -- set enumName__string to enumName
4344 end
4345 enums[str] = i -- set the value of enumName to an ordinal
4346 i = i + 1
4347 end
4348
4349 setmetatable(t, t)
4350 function t.__index(_, k)
4351 local v = enums[k]
4352-- assert(v, "Attempt to access non-existent enum-constant!\nEnum:\t{" .. s .. "}")
4353 return v
4354 end
4355 function t.__newindex()
4356 error("Attempt to alter contents of an enum!\nEnum:\t{" .. s .. "}")
4357 end
4358
4359 return t
4360end
4361
4362return Enum
4363
4364--[=[
4365---declaration:
4366local Stats = Enum [[NAME DESC SPR SPEED HEALTH DAMAGE
4367 WIDTH HEIGHT SOLID OPAQUE MAX_STACK]]
4368
4369---usage:
4370getStat(Stats.NAME) -- getStat(0)
4371getStat(Stats.NAME__string) -- getStat("NAME")
4372
4373Stats.NAME = 3 -- does NOT set, and throws an illegal modification error
4374Stats.FOO = 3 -- does NOT set, and throws an illegal modification error
4375 -- (even though member is also non-existent)
4376
4377getStat(Stats.FOO) -- throws a member non-existent error.
4378--]=]
4379
4380
4381/////////////////Exiting file: Enum.lua/////////////////
4382//--------------------------------------------------------------------------------------------------------
4383/////////////////Entering file: Mixins.lua/////////////////
4384local Mixins = {
4385 _VERSION = "Mixins v1.0.0",
4386
4387 _MADE_FOR_VERSIONS = [[
4388 - middleclass v4.1.1
4389 - MixinEdit v1.0.0
4390 - NamingRevamp v1.0.0
4391 ]],
4392
4393 _DESCRIPTION = "A handful of utilities for creating mixins.",
4394
4395 _URL = [[
4396 NamingRevamp: https://github.com/ActivexDiamond/MixinUtils
4397 ]],
4398
4399 _LICENSE = [[
4400 MIT LICENSE
4401 Copyright (c) 2011 Enrique García Cota
4402 Permission is hereby granted, free of charge, to any person obtaining a
4403 copy of this software and associated documentation files (the
4404 "Software"), to deal in the Software without restriction, including
4405 without limitation the rights to use, copy, modify, merge, publish,
4406 distribute, sublicense, and/or sell copies of the Software, and to
4407 permit persons to whom the Software is furnished to do so, subject to
4408 the following conditions:
4409 The above copyright notice and this permission notice shall be included
4410 in all copies or substantial portions of the Software.
4411 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
4412 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4413 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
4414 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
4415 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
4416 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
4417 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4418 ]],
4419}
4420local print = function() end
4421
4422local function joinInclusions(f1, f2)
4423 print("Joining inclusions.")
4424 return function(self, class)
4425 f1(self, class)
4426 f2(self, class)
4427 end
4428end
4429local function callAll(self, functions)
4430 for _, v in ipairs(functions) do v(self) end
4431end
4432
4433--- @param #table mixin the to add the methods to.
4434-- @param #function ... Any number of functions to call after the class is initialized. Each getting passed the newly created instance as their "self" paramter.
4435function Mixins.onPostInit(mixin, ...)
4436 print("onPostInit")
4437 local functions = {...}
4438 local included = function(self, class)
4439 local new = class.__new
4440 function class:__new(...)
4441 local instance = new(self, ...)
4442 callAll(instance, functions)
4443 return instance
4444 end
4445 end
4446 print("mixin.__included", mixin.__included)
4447 mixin.__included = mixin.__included and
4448 joinInclusions(mixin.__included, included) or included
4449end
4450
4451function Mixins:__call(str)
4452-- return { static = {__mixinName__ = str} }
4453 return {__name__ = str}
4454end
4455
4456setmetatable(Mixins, Mixins)
4457
4458return Mixins
4459
4460/////////////////Exiting file: Mixins.lua/////////////////
4461//--------------------------------------------------------------------------------------------------------
4462/////////////////Entering file: cruxclass.lua/////////////////
4463local middleclass = {
4464 _VERSION = [[
4465 - middleclass v4.1.1
4466 - MixinEdit v1.0.0
4467 - NamingRevamp v1.0.0
4468 ]],
4469
4470 _DESCRIPTION = [[
4471 - Middleclass: Object Orientation for Lua.
4472 - MixinEdit: Updates isInstanceOf and isSubclassOf to handle mixins.
4473 - NamingRevamp: Revamps middleclass's naming conventions to be more uniform.
4474 ]],
4475
4476 _URL = [[
4477 middleclass: https://github.com/kikito/middleclass
4478 MixinEdit: https://github.com/ActivexDiamond/cruxclass
4479 NamingRevamp: https://github.com/ActivexDiamond/cruxclass
4480 ]],
4481
4482 _LICENSE = [[
4483 MIT LICENSE
4484 Copyright (c) 2011 Enrique GarcÃa Cota
4485 Permission is hereby granted, free of charge, to any person obtaining a
4486 copy of this software and associated documentation files (the
4487 "Software"), to deal in the Software without restriction, including
4488 without limitation the rights to use, copy, modify, merge, publish,
4489 distribute, sublicense, and/or sell copies of the Software, and to
4490 permit persons to whom the Software is furnished to do so, subject to
4491 the following conditions:
4492 The above copyright notice and this permission notice shall be included
4493 in all copies or substantial portions of the Software.
4494 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
4495 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4496 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
4497 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
4498 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
4499 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
4500 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4501 ]],
4502
4503 _MIXIN_EDIT_CHANGES = [[
4504 Mixin Additions:
4505 Mixins can also hold fields, not only methods.
4506 Added array "mixins" to all classes.
4507 "include" updates "mixins" field with references
4508 towards the newly included mixins.
4509
4510 "isInstanceOf" checks list of mixins, plus usual operation.
4511 "isSubclassOf" checks list of mixins, plus usual operation.
4512 ]],
4513
4514 _NAMING_REVAMP_CHANGES = [[
4515 Naming Conventions Changes:
4516 + New Conventions:
4517 identifier = keywords, fundamental methods.
4518 __identifier = lua metamethods, middleclass metamethods.
4519 __identifier__ = middleclass internal methods/data.
4520
4521 Fundemental Methods:
4522 "initialise" renamed to "init".
4523 "isInstanceOf" renamed to "instanceof".
4524 "isSubclassOf" renamed to "subclassof".
4525
4526 Middleclass Metamethods:
4527 "allocate" renamed to "__allocate".
4528 "new" renamed to "__new".
4529 "subclassed" renamed to "__subclassed".
4530 "included" renamed to "__included".
4531
4532 Middleclass Internal Data:
4533 "name" renamed to "__name__".
4534 "subclasses" renamed to "__subclasses__".
4535 "__mixins__" renamed to "__mixins__".
4536
4537 Middleclass Internal Methods:
4538 "__instanceDict" renamed to "__instanceDict__".
4539 "__declaredMethods__" renamed to "__declaredMethods__".
4540 ]],
4541
4542 NAMING_REVAMP_PROPOSED_CONVENTIONS = [[
4543 Fields:
4544 private: Enforced, possible getter/setter.
4545 protected: Technically public,
4546 but mutable fields are never accessed directly.
4547 public: All caps,
4548 Only final fields are accessed directly.
4549
4550 Methods:
4551 private: Enforced.
4552 protected: Technically public,
4553 prefixed with a single underscore.
4554 public: "Enforced".
4555
4556 Examples:
4557 local x = 666 -- private
4558 self.x = 42 -- protected
4559 self.PIE = 3.14 -- public
4560
4561 local function getX() -- private
4562 self:_getX() -- protected
4563 self:getX() -- public
4564
4565 Note: "Technically public", as in it CAN be accessed publicly,
4566 security wise, but should never be, following convention.
4567 ]]
4568}
4569
4570local function _createIndexWrapper(aClass, f)
4571 if f == nil then
4572 return aClass.__instanceDict__
4573 else
4574 return function(self, __name__)
4575 local value = aClass.__instanceDict__[__name__]
4576
4577 if value ~= nil then
4578 return value
4579 elseif type(f) == "function" then
4580 return (f(self, __name__))
4581 else
4582 return f[__name__]
4583 end
4584 end
4585 end
4586end
4587
4588local function _propagateInstanceMethod(aClass, __name__, f)
4589 f = __name__ == "__index" and _createIndexWrapper(aClass, f) or f
4590 aClass.__instanceDict__[__name__] = f
4591
4592 for subclass in pairs(aClass.__subclasses__) do
4593 if rawget(subclass.__declaredMethods__, __name__) == nil then
4594 _propagateInstanceMethod(subclass, __name__, f)
4595 end
4596 end
4597end
4598
4599local function _declareInstanceMethod(aClass, __name__, f)
4600 aClass.__declaredMethods__[__name__] = f
4601
4602 if f == nil and aClass.super then
4603 f = aClass.super.__instanceDict__[__name__]
4604 end
4605
4606 _propagateInstanceMethod(aClass, __name__, f)
4607end
4608
4609local function _tostring(self) return "class " .. self.__name__ end
4610local function _call(self, ...) return self:__new(...) end
4611
4612local function _createClass(__name__, super)
4613 local dict = {}
4614 dict.__index = dict
4615
4616 local aClass = { __name__ = __name__, super = super, static = {},
4617 __instanceDict__ = dict, __declaredMethods__ = {},
4618 __subclasses__ = setmetatable({}, {__mode='k'}),
4619 __mixins__ = {} }
4620
4621 if super then
4622 setmetatable(aClass.static, {
4623 __index = function(_,k)
4624 local result = rawget(dict,k)
4625 if result == nil then
4626 return super.static[k]
4627 end
4628 return result
4629 end
4630 })
4631 else
4632 setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
4633 end
4634
4635 setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,
4636 __call = _call, __newindex = _declareInstanceMethod })
4637
4638 return aClass
4639end
4640
4641local function _tableContains(t, o) ----------
4642 for _, v in ipairs(t or {}) do ----------
4643 if v == o then return true end ----------
4644 end ----------
4645 return false ----------
4646end
4647
4648local function _includeMixin(aClass, mixin)
4649 assert(type(mixin) == 'table', "mixin must be a table")
4650
4651 -- If including the DefaultMixin, then class.__mixins__
4652 -- will at that point still be nil.
4653 -- DefaultMixin is not __included in class.__mixins__
4654 if aClass.__mixins__ then table.insert(aClass.__mixins__, mixin) end --------------
4655
4656 for name,method in pairs(mixin) do
4657 if name ~= "__included" and name ~= "static"
4658 and name ~= "__name__" then aClass[name] = method end
4659 end
4660
4661 for name,method in pairs(mixin.static or {}) do
4662 aClass.static[name] = method
4663 end
4664
4665 if type(mixin.__included)=="function" then mixin:__included(aClass) end
4666 return aClass
4667end
4668
4669local DefaultMixin = {
4670 __name__ = "DefaultCruxclassMixin",
4671 __tostring = function(self) return "instance of " .. tostring(self.class) end,
4672
4673 init = function(self, ...) end,
4674
4675 instanceof = function(self, aClass)
4676 return type(aClass) == 'table'
4677 and type(self) == 'table'
4678 and (self.class == aClass
4679 or type(self.class) == 'table'
4680 and (_tableContains(self.class.__mixins__, aClass) ----------
4681 or type(self.class.subclassof) == 'function'
4682 and self.class:subclassof(aClass)))
4683 end,
4684
4685 static = {
4686-- __mixins__ = setmetatable({}, {__mode = 'k'})
4687 __mixins__ = {}, -------------------
4688
4689 __allocate = function(self)
4690 assert(type(self) == 'table', "Make sure that you are using 'Class:__allocate' instead of 'Class.__allocate'")
4691 return setmetatable({ class = self }, self.__instanceDict__)
4692 end,
4693
4694 __new = function(self, ...)
4695 assert(type(self) == 'table', "Make sure that you are using 'Class:__new' instead of 'Class.__new'")
4696 local instance = self:__allocate()
4697 instance:init(...)
4698 return instance
4699 end,
4700
4701 subclass = function(self, __name__)
4702 assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
4703 assert(type(__name__) == "string", "You must provide a __name__(string) for your class")
4704
4705 local subclass = _createClass(__name__, self)
4706
4707 for methodName, f in pairs(self.__instanceDict__) do
4708 _propagateInstanceMethod(subclass, methodName, f)
4709 end
4710 subclass.init = function(instance, ...) return self.init(instance, ...) end
4711
4712 self.__subclasses__[subclass] = true
4713 self:__subclassed(subclass)
4714
4715 return subclass
4716 end,
4717
4718 __subclassed = function(self, other) end,
4719
4720 subclassof = function(self, other)
4721 return type(self) == 'table' and
4722 type(other) == 'table' and
4723 (_tableContains(self.__mixins__, other) or
4724 type(self.super) == 'table' and
4725 (self.super == other or
4726 self.super:subclassof(other)))
4727 end,
4728
4729 include = function(self, ...)
4730 assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
4731 for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
4732 return self
4733 end
4734 }
4735}
4736
4737function middleclass.class(__name__, super)
4738 assert(type(__name__) == 'string', "A __name__ (string) is needed for the __new class")
4739 return super and super:subclass(__name__) or _includeMixin(_createClass(__name__), DefaultMixin)
4740end
4741
4742setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
4743
4744return middleclass
4745
4746--[[
4747Old -> New
4748 __tostring
4749 initialise -> init
4750 isInstanceOf -> instanceof
4751
4752 class
4753
4754 static {
4755 allocate -> __allocate
4756 new -> __new
4757 subclass
4758 subclassed -> __subclassed
4759 isSubclassOf -> subclassof
4760 include
4761
4762 [mixin]included -> __included
4763 [+] __mixins__
4764
4765 name -> __name__
4766 super
4767 __instanceDict -> __instanceDict__
4768 __declaredMethods> __declaredMethods__
4769 subclasses - __subclasses__
4770
4771----------------------------------------
4772
4773 mthd = keywords: super, class, static
4774 instanceof, subclassof
4775 fundementals: init, subclass, include
4776
4777 __mthd = metamethods: __tostring,
4778 middleclass_metamethods: __allocate,
4779 __new, __subclassed, __included
4780
4781
4782 __mthd__ = middleclass_internal_methods: __instanceDict__,
4783 __declaredMethods__
4784 middleclass_internal_data: __name__,
4785 __subclasses__, __mixins__
4786
4787--]]
4788
4789--[[
4790Fields:
4791 private: Enforced, possible getter/setter.
4792 protected: Technically public,
4793 but fields are never accessed directly.
4794 public: Fields are never public.
4795
4796Methods:
4797 private: Enforced.
4798 protected: Technically public,
4799 prefixed with a single underscore.
4800 public: "Enforced".
4801
4802Examples:
4803 local x = 3.14 -- private
4804 self.x = 42 -- protected
4805
4806 local function getX() -- private
4807 self:_getX() -- protected
4808 self:getX() -- public
4809--]]
4810
4811/////////////////Exiting file: cruxclass.lua/////////////////
4812//--------------------------------------------------------------------------------------------------------
4813/////////////////Entering file: cruxclass_test.lua/////////////////
4814local class = require "libs.cruxclass"
4815local Obj = class("Obj")
4816
4817function Obj:init(x, y)
4818 self.x = x
4819 self.y = y
4820end
4821
4822function Obj:echo() print(self.x, self.y) end
4823
4824local obj = Obj(3, 3)
4825obj:echo()
4826obj.x = 2
4827obj:echo()
4828
4829local case;
4830
4831for k, v in pairs(Obj.__mixins__) do print(k, v) end
4832
4833local Mixin = {}
4834function Mixin:mixEcho() print(self.class.name) end
4835local Obj = Obj:include(Mixin)
4836local Obj = Obj:include(Mixin)
4837
4838for k, v in pairs(Obj.__mixins__) do print(k, v) end
4839
4840local obj2 = Obj(4, 4)
4841obj2:mixEcho()
4842
4843case = obj2:instanceof(Obj)
4844print(case)
4845case = obj2.class:subclassof(Obj)
4846print(case)
4847
4848print(obj.__mixins__)
4849print(obj2.__mixins__)
4850print(Obj.__mixins__)
4851
4852
4853case = obj:instanceof(Mixin)
4854print(case)
4855case = obj2:instanceof(Mixin)
4856print(case)
4857case = Obj:instanceof(Mixin)
4858print(case)
4859
4860print "-----"
4861case = obj.class:subclassof(Mixin)
4862print(case)
4863case = obj2.class:subclassof(Mixin)
4864print(case)
4865case = Obj:subclassof(Mixin)
4866print(case)
4867
4868 instanceof = function(sel, aClass)
4869 return type(aClass) == 'table'
4870 and type(sel) == 'table'
4871 and (sel.class == aClass
4872 or type(sel.class) == 'table'
4873 and (_tableContains(sel.class.__mixins__, aClass) ----------
4874 or type(sel.class.subclassof) == 'function'
4875 and sel.class:subclassof(aClass)))
4876 end
4877
4878local Tickable = {tick = function() end }
4879local Furnace = class("Furnace"):include(Tickable)
4880local Pulv = class("Pulv", Furnace)
4881
4882print "=========="
4883case = Furnace:subclassof(Furnace)
4884print(case)
4885case = Furnace:subclassof(Tickable)
4886print(case)
4887
4888print "----------"
4889
4890case = Pulv:subclassof(Furnace)
4891print(case)
4892case = Pulv:subclassof(Tickable)
4893print(case)
4894
4895
4896
4897--[[
4898
4899local ITickable = Mixin("ITickable")
4900
4901local ITickable = {}
4902
4903function ITickable:tick()
4904
4905 --do stuff
4906
4907end
4908
4909
4910local Skeleton = class("Skeleton", Mob):include(ITickable)
4911
4912
4913local skeleton = Skeleton()
4914
4915skeleton:tick() --ticks
4916
4917
4918function tickAll(entities)
4919
4920 for _, v in ipairs(entities) do
4921
4922 if v.super:
4923
4924 end
4925
4926end
4927
4928
4929obj:instanceof(class/mixin) -- takes a class, or a mixin
4930
4931 searches entire class heirarchy,
4932
4933 and thus searching entire list of __mixins__ for every
4934
4935 class in the heirarchy
4936
4937 returns false if passed an instance
4938
4939
4940
4941Obj:subclassof(class/mixin) -- takes a class, or a mixin
4942
4943 searches entire class heirarchy,
4944
4945 and thus searching entire list of __mixins__ for every
4946
4947 class in the heirarchy
4948
4949 returns false if passed an instance
4950--]]
4951
4952/////////////////Exiting file: cruxclass_test.lua/////////////////
4953//--------------------------------------------------------------------------------------------------------
4954/////////////////Entering file: middleclass_test.lua/////////////////
4955local class = require 'middleclass'
4956
4957 DrinksCoffee = {static = {}}
4958
4959 -- This is another valid way of declaring functions on a mixin.
4960 -- Note that we are using the : operator, so there's an implicit self parameter
4961 function DrinksCoffee:drink(drinkTime)
4962 if(drinkTime~=self.class.coffeeTime) then
4963 print(self.name .. ': It is not the time to drink coffee!')
4964 else
4965 print(self.name .. ': Mmm I love coffee at ' .. drinkTime)
4966 end
4967 end
4968
4969
4970 -- the included method is invoked every time DrinksCoffee is included on a class
4971 -- notice that paramters can be passed around
4972 function DrinksCoffee:included(klass)
4973 print(klass.name .. ' drinks coffee at ' .. klass.coffeeTime)
4974 klass.static.x = 0
4975 klass.static.x = klass.static.x + 1
4976 print('x', klass.x)
4977 end
4978
4979 EnglishMan = class('EnglishMan')
4980 EnglishMan.static.coffeeTime = 5
4981 EnglishMan:include(DrinksCoffee)
4982 function EnglishMan:init(name) self.name = name end
4983 EnglishMan.y = 1
4984 EnglishMan.static.z = 1
4985
4986 Spaniard = class('Spaniard')
4987 Spaniard.static.coffeeTime = 6
4988 Spaniard:include(DrinksCoffee)
4989 function Spaniard:init(name) self.name = name end
4990
4991 tom = EnglishMan:new('tom')
4992 juan = Spaniard:new('juan')
4993
4994-- EnglishMan:drink(5)
4995 tom:drink(5)
4996 juan:drink(5)
4997 juan:drink(6)
4998
4999 print(tom.x)
5000 print(EnglishMan.x)
5001 print("---")
5002 print('y', tom.y)
5003 print('sy', EnglishMan.y)
5004 print('z', tom.z)
5005 print('sz', EnglishMan.z)
5006
5007
5008
5009/////////////////Exiting file: middleclass_test.lua/////////////////
5010//--------------------------------------------------------------------------------------------------------
5011/////////////////Entering file: misc.lua/////////////////
5012
5013local misc = {}
5014
5015------------------------------ Color Mapping ------------------------------
5016local function mapColor(min, max, nmin, nmax, ...)
5017 local c = type(...) == "table" and ... or {...}
5018 local rc = {}
5019 for i = 1, 4 do
5020 local v = c[i] or max
5021 rc[i] = misc.map(v, min, max, nmin, nmax)
5022 end
5023 return rc
5024end
5025
5026--- @param #color ... Either a table {r, g, b, a}, or direct r, g, b, a values.
5027-- Missing values default to 255
5028-- @return #color It's input mapped from [0, 255] to [0, 1].
5029function misc.toLoveColor(...)
5030 return mapColor(0, 255, 0, 1, ...)
5031end
5032
5033--- @param #color ... Either a table {r, g, b, a}, or direct r, g, b, a values.
5034-- Missing values default to 1
5035-- @return #color It's input mapped to from [0, 1] to [0, 255].
5036function misc.to8bitColor(...)
5037 return mapColor(0, 1, 0, 255, ...)
5038end
5039
5040------------------------------ Misc Math ------------------------------
5041function misc.map(x, min, max, nmin, nmax)
5042 return (x - min) * (nmax - nmin) / (max - min) + nmin
5043end
5044
5045function misc.constrain(x, min, max)
5046 return math.max(math.min(x, max), min)
5047end
5048
5049------------------------------ Conversion Methods ------------------------------
5050function misc.toBin(n, bits, seg, space, sep)
5051 local t, s, nb = {}, seg
5052 local space = space or ' '
5053 if n == 0 then nb = 1
5054 else nb = math.floor(math.log(n) / math.log(2)) + 1 end --neededBits = roundUp(log2(n))
5055
5056 for b = nb, 1, -1 do
5057 local rest = math.fmod(n, 2)
5058 table.insert(t, 1, rest)
5059 if seg then
5060 s = s - 1
5061 if s == 0 then table.insert(t, 1, space) ; s = seg end
5062 end
5063 n = (n - rest) / 2
5064 end
5065
5066 if bits and bits > nb then
5067 for i = 1, bits - nb do
5068 table.insert(t, 1, '0')
5069 if seg then
5070 s = s - 1
5071 if s == 0 then table.insert(t, 1, space) ; s = seg end
5072 end
5073 end
5074 end
5075
5076 return table.concat(t, sep)
5077end
5078
5079------------------------------ Lua-Related ------------------------------
5080function misc.selectArg(t, ...) --selectArg(type, args)
5081 local i, p = 1, tonumber(t:sub(1, 1))
5082 if type(p) == 'number' then
5083 i, t = p, t:sub(2, -1)
5084 end
5085
5086 if t == 's' then t = 'string'
5087 elseif t == 'n' then t = 'number'
5088 elseif t == 'f' then t = 'function'
5089 elseif t == 't' then t = 'table'
5090 elseif t == 'ni' then t = 'nil'
5091 elseif t == 'th' then t = 'thread'
5092 elseif t == 'u' then t = 'userdata' end
5093 for k, v in ipairs({...}) do
5094 if type(v) == t then i = i - 1; if i == 0 then return v end end
5095 end
5096end
5097
5098do
5099 ---Create Helpers
5100 local function createHelpers(stack)
5101 local cur = function() return type(stack[1]) end
5102 local pop = function(t) return table.remove(t or stack, 1) end
5103 local add = function(t, obj) return table.insert(t or stack, obj) end
5104 return cur, pop, add
5105 end
5106
5107 ---Get Flag
5108 local function getFlag(fParams)
5109 local flag;
5110 local cur, pop, add = createHelpers(fParams)
5111 if cur() == 'string' then
5112 local arg1 = fParams[1]
5113 flag = arg1:sub(1, 1) == '-' and arg1 or nil
5114 end
5115 if flag then pop() end
5116 return flag
5117 end
5118
5119 ---Cleaners
5120 local function cleanupFuncArgs(fCleanup, fArgs)
5121 if fCleanup == -1 or not fArgs then return fArgs end
5122 local cur, pop, add = createHelpers(fCleanup)
5123 local cleanFuncArgs = {}
5124 local cleaner = pop()
5125 if #fCleanup == 0 then
5126 for k, v in ipairs(fArgs) do cleanFuncArgs[k] = cleaner(v) end
5127 else
5128 cleanFuncArgs = fArgs
5129 for _, i in ipairs(fCleanup) do
5130 cleanFuncArgs[i] = cleaner(fArgs[i])
5131 end
5132 end
5133 return cleanFuncArgs
5134 end
5135
5136 local function cleanupAllArgs(...)
5137 local args = {...}
5138 local cur, pop, add = createHelpers(args)
5139 local commonArgs, cleanCommonArgs
5140 local funcs, fParams, fCleanups = {}, {}, {}
5141
5142 commonArgs = pop()
5143 if cur() == 'table' then
5144 local cct = pop() --common-cleaner-table
5145 local cleaner = pop(cct) --common-cleaner
5146 if #cct == 0 then
5147 for k, v in ipairs(commonArgs) do
5148 cleanCommonArgs[k] = cleaner(v)
5149 end
5150 else
5151 cleanCommonArgs = commonArgs
5152 for _, i in ipairs(cct) do
5153 cleanCommonArgs[i] = cleaner(commonArgs[i])
5154 end
5155 end
5156 else cleanCommonArgs = commonArgs end
5157
5158 for i = 1, #args / 2 do
5159 add(funcs, pop())
5160 add(fParams, pop())
5161 if cur() == 'table' then add(fCleanups, pop())
5162 else add(fCleanups, -1) end
5163 end
5164 return cleanCommonArgs, funcs, fParams, fCleanups
5165 end
5166
5167 ---Check Eligibility
5168 local function checkLuaVal(p, arg)
5169 local t = type
5170 if p == 's' then p = 'string'
5171 elseif p == 'n' then p = 'number'
5172 elseif p == 'f' then p = 'function'
5173 elseif p == 't' then p = 'table'
5174 elseif p == 'ni' then p = 'nil'
5175 elseif p == 'th' then p = 'thread'
5176 elseif p == 'u' then p = 'userdata' end
5177
5178 if p == t(arg) then return true
5179 else return false end
5180 end
5181
5182 local function checkObject(p, arg)
5183 p = p.class or p
5184 return type(arg) == 'table' and arg.instanceof and arg:instanceof(p)
5185 end
5186
5187 local function checkParam(p, arg)
5188 if type(p) == 'string' then return checkLuaVal(p, arg)
5189 elseif type(p) == 'table' then return checkObject(p, arg) end
5190 end
5191
5192 local function checkNoFlag(cleanArgs, func, fParams)
5193 local found, lastFoundIndex = {}, 0
5194 local missing = #fParams
5195 for i, param in ipairs(fParams) do
5196 for k, arg in ipairs(cleanArgs) do
5197 if missing > 0 and k >= i and checkParam(param, arg) then
5198 table.insert(found, arg)
5199 missing = missing - 1
5200 lastFoundIndex = k
5201 print(i, k, missing, lastFoundIndex, #found)
5202 break
5203 end
5204 end
5205-- print('?')
5206 end
5207
5208 if lastFoundIndex > 0 then
5209 for i = lastFoundIndex + 1, #cleanArgs do
5210 table.insert(found, cleanArgs[i])
5211 end
5212 end
5213 if missing == 0 then return func, found
5214 else return nil end
5215 end
5216
5217 local function checkMinimal(cleanArgs, func, fParams)
5218-- TODO: Implement -m flag.
5219 error "TODO: Implement -m flag in misc.overload."
5220 end
5221
5222 local function checkStrict(cleanArgs, func, fParams)
5223-- TODO: Implement -s flag.
5224 error "TODO: Implement -s flag in misc.overload."
5225 end
5226
5227 ---Overload
5228 function misc.ovld(...)
5229 local cleanArgs, funcs, fParams, fCleanups = cleanupAllArgs(...)
5230 local cur, pop, add = createHelpers(cleanArgs)
5231
5232 if DEBUG.OVERLOAD then
5233 utils.t.print("cleanArgs", cleanArgs)
5234 utils.t.print("funcs", funcs)
5235 utils.t.print("fParams", fParams)
5236 utils.t.print("fCleanups", fCleanups)
5237 utils.t.print("{...}", {...})
5238 end
5239
5240 for k, func in ipairs(funcs) do
5241 local flag = getFlag(fParams[k])
5242 local check, fArgs, cleanFuncArgs;
5243 if not flag then check = checkNoFlag
5244 elseif flag == '-m' then check = checkMinimal
5245 elseif flag == '-s' then check = checkStrict end
5246 check, fArgs = check(cleanArgs, func, fParams[k])
5247 if check then
5248 local cleanFuncArgs = cleanupFuncArgs(fCleanups[k], fArgs)
5249 return check(unpack(cleanFuncArgs))
5250 end
5251 end
5252 end
5253end
5254return misc
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272/////////////////Exiting file: misc.lua/////////////////
5273//--------------------------------------------------------------------------------------------------------
5274/////////////////Entering file: Set.lua/////////////////
5275return function(...) -- Set()
5276 local self = {...}
5277
5278 function self.add(o)
5279 if self.contains(o) then return end
5280 table.insert(self, o)
5281 end
5282
5283 function self.remove(o)
5284 for k, v in ipairs(self) do
5285 if v == o then
5286 table.remove(self, k)
5287 return o
5288 end
5289 end
5290 end
5291
5292 function self.contains(o)
5293 for k, v in ipairs(self) do
5294 if v == o or (v.equals and v.equals(o)) then
5295 return true end
5296 end
5297 return false
5298 end
5299
5300 return self
5301end
5302
5303
5304/////////////////Exiting file: Set.lua/////////////////
5305//--------------------------------------------------------------------------------------------------------
5306/////////////////Entering file: tables.lua/////////////////
5307local tables = {}
5308
5309------------------------------ addByIndex ------------------------------
5310---insert all contents of t2+..., into t1. Using the same keys/indices that t2 used,
5311--override if necessary.
5312function tables.fAddByIndex(...)
5313 local args = {...}
5314 local t = args[1]
5315 for i = 1, #args do
5316 for k, v in pairs(args[i]) do
5317 t[k] = v
5318 end
5319 end
5320end
5321
5322function tables.addByIndex(...)
5323 local args = {...}
5324 local t = args[1]
5325 for i = 1, #args do
5326 for k, v in pairs(args[i]) do
5327 if not t[k] then t[k] = v end
5328 end
5329 end
5330end
5331
5332------------------------------ Non-Mutating AddByIndex ------------------------------
5333---return new table containing a combinations of t1 and t2 ...
5334--override if necessary.
5335--similar to table.fAddByIndex, except it returns a new table, not altering t1/t2.
5336--non-mutating, forced, addByIndex.
5337function tables.nfAddByIndex(...)
5338 local args = {...}
5339 local t = {}
5340
5341 for i = 1, #args do
5342 for k, v in pairs(args[i]) do
5343 t[k] = v
5344 end
5345 end
5346 return t
5347end
5348
5349------------------------------ Misc. Utils ------------------------------
5350function tables.clone(t2)
5351 local t = {}
5352 for k, v in pairs(t2) do
5353 t[k] = v
5354 end
5355 return t
5356end
5357
5358function tables.isEmpty(t)
5359 local b = true
5360 for _, _ in pairs(t) do
5361 b = false
5362 end
5363 return b
5364end
5365
5366function tables.isEmptyDeep(t)
5367 local b = true
5368 for _, v in pairs(t) do
5369 if type(v) == 'table' then
5370 b = tables.isEmptyDeep(v)
5371 else b = false end
5372 end
5373 return b
5374end
5375
5376------------------------------ Debug-Utils ------------------------------
5377---Prints the all k, v pairs in the given table(s).
5378function tables.print(...)
5379 local args = {...}
5380 local n, ind
5381
5382 local function indent(n)
5383 n = n or 0
5384 n = n * 4
5385 for i = 1, n do
5386 io.write(" ")
5387 end
5388 end
5389
5390 if type(args[1]) == 'string' then
5391 if type(args[2]) == 'number' then
5392 ind = args[2]
5393 n = 3
5394 else n = 2 ind = 0 end
5395
5396 indent(ind)
5397 io.write(" -----" .. args[1] .. "-----")
5398 else
5399 n = 1
5400 ind = 0
5401 io.write(" --------------")
5402 end
5403
5404 local t = args[n]
5405 if type(t) ~= 'table' then
5406 io.write('\n')
5407 indent(ind)
5408 print(" table is nil.")
5409 elseif tables.isEmpty(t) then
5410 io.write('\n')
5411 indent(ind)
5412 print(" table is empty.")
5413 end
5414
5415 for i = n, #args do
5416 if not tables.isEmpty(args[i]) then
5417 io.write("\n")
5418 for k, v in pairs(args[i]) do
5419 if type(v) == 'table' then
5420 tables.print(tostring(k), ind + 4, v)
5421 else
5422 indent(ind)
5423 local index = i - (n-1)
5424 if ind == 0 then io.write(" t" .. index .. ": ")
5425 else io.write(" t" .. index .. "-" .. ind/4 .. ": ") end
5426 io.write(k)
5427 io.write(" = ")
5428 print(v)
5429 end
5430 end
5431 end
5432 end
5433 indent(ind)
5434 io.write("<------------->\n")
5435 if ind == 0 then io.write('\n') end
5436end
5437
5438return tables
5439
5440/////////////////Exiting file: tables.lua/////////////////
5441//--------------------------------------------------------------------------------------------------------
5442/////////////////Entering file: main.lua/////////////////
5443--require "box2dMeterTest"
5444---[[
5445require "DEBUG"
5446require "globals"
5447
5448local Registry = require "istats.Registry"
5449
5450local Block = require "template.Block"
5451local Entity = require "template.Entity"
5452local Player = require "template.Player"
5453local Zombie = require "template.Zombie"
5454
5455local Evsys = require "evsys.Evsys"
5456local KeypressEvent = require "evsys.input.KeypressEvent"
5457
5458local Item = require "template.Item"
5459local ItemStack = require "inv.ItemStack"
5460local Slot = require "inv.Slot"
5461
5462local Scheduler = require "utils.Scheduler"
5463local Game = require "core.Game"
5464
5465local blocks = {}
5466local player
5467local zombie, zombie1, zombie2
5468
5469function love.load()
5470
5471 local grid = {0, 0,
5472 2, 2,
5473 18, 13,
5474 9, 9,
5475 8, 8,
5476 4, 4,
5477-- 20, 14,
5478 21, 15,
5479
5480 3, 8,
5481 3, 10,
5482
5483 3, 11,
5484 3, 12, 4, 12,
5485 3, 13, 4, 13, 5, 13,
5486 3, 14, 4, 14, 5, 14, 6, 14,
5487 3, 15, 4, 15, 5, 15, 6, 15, 7, 15,
5488 }
5489
5490 for i = 1, 20 do
5491 local x, y = 2 + i, 16
5492 table.insert(grid, x)
5493 table.insert(grid, y)
5494 end
5495
5496 for i = 1, 20 do
5497 local x, y = 22, i
5498 table.insert(grid, x)
5499 table.insert(grid, y)
5500
5501 local x, y = 2, i
5502 table.insert(grid, x)
5503 table.insert(grid, y)
5504 end
5505
5506 for i = 1, #grid, 2 do
5507 table.insert(blocks,
5508 Block("andesiteStoneblock", grid[i], grid[i + 1]))
5509 end
5510
5511 player = Player(12, 12)
5512 zombie = Zombie(16, 12)
5513-- zombie1 = Zombie(17, 12)
5514-- zombie2 = Zombie(18, 12)
5515-- local interval, total = -1, 0.5
5516-- local interval, total = 0.5, 5
5517-- function getClosure0(dt, ...)
5518-- local tdt = 0
5519-- local fdt = 0
5520-- local x = 0
5521-- return function (dt)
5522-- x = x + 1
5523-- print('ping' .. x)
5524--
5525-- if x == 1 then fdt = dt end
5526-- tdt = tdt + dt
5527-- local round = interval == -1 and 0 or interval
5528-- local per = math.min(tdt / (total - round), 1)
5529-- local per = tdt / (total - round)
5530-- print('dt', dt, 'tdt', tdt, 'per', per)
5531-- end
5532-- end
5533--
5534-- local getTime = love.timer.getTime
5535-- function getClosure1(dt, ...)
5536-- local stamp = getTime()
5537-- local x = 0
5538-- return function (dt)
5539-- x = x + 1
5540-- print('ping' .. x)
5541-- local tdt = getTime() - stamp
5542-- local round = interval == -1 and 0 or interval
5543-- local per = math.min(tdt / (total - round), 1)
5544-- local per = tdt / (total - round)
5545-- print('dt', dt, 'tdt', tdt, 'per', per)
5546-- end
5547-- end
5548--
5549-- function getClosure2(dt, ...)
5550-- local tdt = 0
5551-- return function (dt)
5552-- tdt = tdt + dt
5553-- local round = interval == -1 and 0 or interval
5554-- local per = math.min(tdt / (total - round), 1)
5555-- local per = tdt / (total - round)
5556-- print('dt', dt, 'tdt', tdt, 'per', per)
5557-- end
5558-- end
5559-- Scheduler:callEveryFor(interval, total, getClosure0())
5560--
5561-- Scheduler:callEveryFor(interval, total, getClosure0(), nil, function()
5562-- print('-----------------')
5563-- Scheduler:callEveryFor(interval, total, getClosure1())
5564-- end)
5565--
5566-- p = 0
5567-- function f3(dt, per)
5568-- p = p + 1
5569-- print('ping' .. p, 'dt', dt, 'per', per)
5570-- end
5571--
5572-- Scheduler:callEveryFor(interval, total, f3)
5573--
5574-- DEBUG / TEST CODE
5575--print ((15 / 30) % 1)
5576-- print (4.3 % 2)
5577-- print (1.3 % 2)
5578-- x = 0
5579-- function f0()
5580-- x = x + 1
5581-- print ("ping:" .. x)
5582-- end
5583--
5584-- function f1(...) f0(); print(...) end
5585--
5586-- function done(x) print("WRAPUP: ", x) end
5587--
5588-- Scheduler:callAfter(5, f0)
5589-- Scheduler:callAfter(6, f1)
5590-- Scheduler:callAfter(6, f1, {'x'})
5591--
5592-- Scheduler:callFor(0.5, f0)
5593--
5594-- Scheduler:callEveryFor(1, 10, f1)
5595-- Scheduler:callEveryFor(0.1, 1, f1)
5596--
5597-- Scheduler:callAfter(2, f0, nil, done, 42)
5598-- Scheduler:callFor(0.1, f0, nil, done, 42)
5599-- Scheduler:callEvery(0.5, f0, nil, done, 42)
5600-- Scheduler:callEveryFor(0.1, 1, f0, nil, done, 42)
5601--
5602-- Scheduler:callFor(6, f1)
5603-- Scheduler:callFor(6, f1, {'x'})
5604--
5605--
5606-- area = {3, 4, 5, 6}
5607-- print(1, 2, unpack(area), 7, 8)
5608--
5609-- function test(...)
5610-- args = {...}
5611-- print(unpack(args), 3)
5612-- end
5613-- test(1, 2)
5614--
5615-- function rect()
5616-- print('rect')
5617-- love.graphics.setColor(1, 1, 1, 1)
5618-- love.graphics.rectangle('fill', 3, 3, 3, 3)
5619-- end
5620-- Scheduler:gCallEveryFor(2, 30, rect)
5621
5622end
5623
5624local function cleanupArgs(from)
5625
5626end
5627
5628local function combineItem(item, ...)
5629 print("combineItem", item, ...)
5630end
5631
5632local function combineNumber(n, ...)
5633 print("combineNumber", n, ...)
5634end
5635
5636local function combineTable(t, ...)
5637 print("combineTable", t, ...)
5638end
5639
5640local function combineString(str, ...)
5641 print("combineString", str, ...)
5642end
5643
5644local function combineTableString(t, str, ...)
5645 print("combineTableString", t, str, ...)
5646end
5647
5648local function combine(...)
5649 return utils.ovld({...}, --args
5650-- {cleanupArgs}, --optional cleanup function[1]
5651 combineItem, {Item},
5652 combineTableString, {'t', 's'},
5653 combineTable, {'t'},
5654 combineString, {'s'},
5655 combineNumber, {'n'}
5656 )
5657
5658
5659end
5660
5661combine(1, 2, 3)
5662combine({x = 3}, 2, 3)
5663combine(-1, "str", "str2", 2, 3, "str3")
5664combine({x = 30}, "strT", 20, 30)
5665
5666--local log = Item("logOak")
5667--combine(1, log, 3)
5668
5669--love.timer.sleep(1000)
5670
5671local log = Item("logOak")
5672local stack = ItemStack(log)
5673local slot = Slot(nil, nil, stack)
5674
5675print(stack:getItem(), stack:getAmount(), stack:getParent())
5676print(slot:getItemStack(), slot:getCapacity(), slot:getParent())
5677print(slot.child.child:getMaxStack())
5678local dir = 0;
5679function love.update(dt)
5680 Game:tick(dt)
5681
5682 player:tick(dt)
5683 zombie:tick(dt)
5684-- zombie1:tick(dt)
5685-- zombie2:tick(dt)
5686 Scheduler:tick(dt)
5687 Evsys:poll()
5688end
5689
5690local clicks = 0
5691function love.draw()
5692 local g = love.graphics;
5693 g.scale(Game.MS)
5694
5695 for _, v in ipairs(blocks) do
5696 v:draw(g)
5697 end
5698
5699 Scheduler:draw(g)
5700
5701 player:draw(g)
5702 zombie:draw(g)
5703-- zombie1:draw(g)
5704-- zombie2:draw(g)
5705
5706 g.setColor(1, 1, 1, 1)
5707 g.scale(1/Game.MS)
5708 local vx, vy = player.body:getLinearVelocity()
5709 local str = string.format("vx: %f | vy: %f ", vx, vy)
5710 g.print(str, 40, 80)
5711
5712 local s = player.state;
5713 local air = s:is(Player.AIRBORNE)
5714 local str = string.format("Player.AIRBORNE: %s", air)
5715 g.print(str, 40, 100)
5716
5717 local jump = s:is(Player.JUMPING)
5718 local str = string.format("Player.JUMPING: %s", jump)
5719 g.print(str, 40, 120)
5720
5721 local jr = player.jumpsRemaining
5722 local str = string.format("Player.jumpsRemaining: %d", jr)
5723 g.print(str, 40, 140)
5724
5725 local ej = player.extraJumps
5726 local str = string.format("Player.extraRemaining: %d", ej)
5727 g.print(str, 40, 160)
5728
5729 str = string.format("grid: %d, %d", Game:scaledSnap(mousex) / Game.GRID,
5730 Game:scaledSnap(mousey) / Game.GRID)
5731 g.print(str, 40, 180)
5732end
5733
5734
5735function love.keypressed(k, code, isrepeat)
5736 Evsys:queue(KeypressEvent(k))
5737 clicks = clicks + 1
5738end
5739
5740mousex, mousey = 0, 0
5741function love.mousemoved(x, y, dx, dy, istouch)
5742 mousex, mousey = x, y
5743end
5744
5745
5746--]]
5747
5748/////////////////Exiting file: main.lua/////////////////
5749//--------------------------------------------------------------------------------------------------------
5750/////////////////Entering file: Block.lua/////////////////
5751local class = require "libs.cruxclass"
5752local WorldObj = require "template.WorldObj"
5753local IBoundingBox = require "behavior.IBoundingBox"
5754
5755local Game = require "core.Game"
5756--local Registry = require "istats.Registry"
5757
5758------------------------------ Constructor ------------------------------
5759local Block = class("Block", WorldObj)
5760function Block:init(id, x, y)
5761 WorldObj.init(self, id, Game:snap(x), Game:snap(y), 'static')
5762end
5763
5764------------------------------ Main Methods ------------------------------
5765function Block:draw(g)
5766 g.setColor(1, 0, 0, 1)
5767 g.polygon('fill', self.body:getWorldPoints(self.shape:getPoints()))
5768end
5769
5770------------------------------ @Override Setters ------------------------------
5771---Overrides - Position Snapping
5772function Block:setX(x) WorldObj.setX(Game:snap(x)) end
5773function Block:setY(y) WorldObj.setY(Game:snap(y)) end
5774function Block:setPos(x, y) self:setX(x); self:setY(y) end
5775
5776--TODO: Perhaps override dimension-setters to also snap?
5777
5778return Block
5779
5780/////////////////Exiting file: Block.lua/////////////////
5781//--------------------------------------------------------------------------------------------------------
5782/////////////////Entering file: Entity.lua/////////////////
5783local class = require "libs.cruxclass"
5784local WorldObj = require "template.WorldObj"
5785local IBoundingBox = require "behavior.IBoundingBox"
5786
5787--local Game = require "core.Game"
5788--local Registry = require "istats.Registry"
5789
5790local Entity = class("Entity", WorldObj)
5791function Entity:init(id, x, y)
5792 WorldObj.init(self, id, x, y, 'dynamic')
5793end
5794
5795return Entity
5796
5797/////////////////Exiting file: Entity.lua/////////////////
5798//--------------------------------------------------------------------------------------------------------
5799/////////////////Entering file: Item.lua/////////////////
5800local class = require "libs.cruxclass"
5801local Thing = require "template.Thing"
5802
5803local IContainable = require "inv.IContainable"
5804
5805------------------------------ Helper Methods ------------------------------
5806
5807------------------------------ Constructor ------------------------------
5808local Item = class("Item", Thing):include(IContainable)
5809function Item:init(id, parent)
5810 Thing.init(self, id)
5811 self.parent = parent
5812end
5813
5814------------------------------ Constants ------------------------------
5815Item.TINY, Item.SMALL, Item.MEDIUM, Item.LARGE, Item.HUGE = 1, 2, 3, 4, 5
5816
5817------------------------------ API ------------------------------
5818
5819
5820------------------------------ Utils ------------------------------
5821function Item:cloneTags() return utils.t.clone(self:getTags()) end
5822
5823------------------------------ Object-Common Methods ------------------------------
5824function Item:clone()
5825 return Item(self.id)
5826end
5827
5828return Item
5829
5830/////////////////Exiting file: Item.lua/////////////////
5831//--------------------------------------------------------------------------------------------------------
5832/////////////////Entering file: MeleeWeapon.lua/////////////////
5833local class = require "libs.cruxclass"
5834local Thing = require "template.Thing"
5835
5836--local Registry = require "istats.Registry"
5837
5838------------------------------ Constructor ------------------------------
5839local MeleeWeapon = class("MeleeWeapon", Thing)
5840function MeleeWeapon:init(id)
5841 Thing.init(self, id)
5842-- print('weapon', #self.hitbox)
5843end
5844
5845------------------------------ Constants ------------------------------
5846
5847return MeleeWeapon
5848
5849--[[
5850 Example:
5851hitbox {
5852 {
5853 dur = 10
5854 anchor = origin / center / center-aligned
5855 area = {x, y, w, h}
5856transition = instant / linear-grow
5857 }
5858
5859 {
5860
5861 }
5862}
5863
5864
5865
5866Definite lists:
5867 Combat -> Melee-Weapons, Ranged-Weapons, Stomping, Projectiles
5868
5869 Inventory -> Template Classes, Basic Inventory Interfaces,
5870
5871 Crafting
5872
5873 Rendering -> Basic Drawing Interfaces
5874
5875 GUI
5876
5877 World
5878
5879 Entities -> Basic Movement Interfaces
5880
5881
5882Potential Lists:
5883 Player
5884
5885 Entities / Mobs / Movement / Physics
5886
5887 Saving / Serialization
5888
5889
5890Item
5891Slot, ItemStack
5892(Item/Block bridges)
5893Inventory (?)
5894IStorage
5895
5896IWalk, IJump, IFly
5897
5898
5899
5900
5901--]]
5902
5903/////////////////Exiting file: MeleeWeapon.lua/////////////////
5904//--------------------------------------------------------------------------------------------------------
5905/////////////////Entering file: Mob.lua/////////////////
5906local class = require "libs.cruxclass"
5907local Entity = require "template.Entity"
5908local IBoundingBox = require "behavior.IBoundingBox"
5909
5910local MultiState = require "core.MultiState"
5911
5912--local Game = require "core.Game"
5913--local Registry = require "istats.Registry"
5914
5915------------------------------ Helper Methods ------------------------------
5916local function sign(x)
5917 return x > 0 and 1 or x < 0 and -1 or 0
5918end
5919local function reqF(s, v, m, dt)
5920 local x = s - v;
5921 if (0 > s and s > v) or (0 < s and s < v) then x = 0 end
5922 local a = x/dt
5923 local f = a*m
5924 return f
5925end
5926
5927local function move(self, sx, sy, dt)
5928 local m = self.body:getMass()
5929 local vx, vy = self.body:getLinearVelocity()
5930 ---For an axis that is passed as nil, f = 0.
5931 local fx, fy = sx and reqF(sx, vx, m, dt) or 0, sy and reqF(sy, vy, m, dt) or 0
5932 self.body:applyForce(fx, fy)
5933end
5934--[[
5935 final equation:
5936 [dif] x = s - v
5937 if (s neg AND s > v) OR (s pos AND s < v)
5938 x = 0
5939 f = toForce(x)
5940 body->applyForce(f)
5941
5942 goal:
5943 move -> vel >= speed (aka max moving velocity)
5944 get current vel
5945 get goal vel (speed)
5946 if vel >= speed ;
5947 do nothing
5948 if vel < speed ;
5949 apply enough force to accelerate
5950 to speed in 1 tick
5951 => go from 'goal velocity' (speed) to force to apply
5952
5953 physics cheatsheet:
5954 a = v/t
5955 f = am
5956
5957 f = ma
5958 v = at
5959 a = dv/dt ; dv = a * dt
5960
5961 --------- examples --------------
5962
5963 -- right
5964 v = 2 ; s = 3 -> 1
5965 v = 4 ; s = 3 -> 0
5966
5967 dif: s - v
5968 [3 - 2] 1 (apply)
5969 [3 - 4] -1 (x < v)
5970
5971 -- left
5972 v = -2 ; s = -3 -> -1
5973 v = -4 ; s = -3 -> 0
5974
5975 dif: s - v
5976 [-3 - -2] -1 (apply)
5977 [-3 - -4] 1 (x > v)
5978
5979 -- right TO left
5980 v = 2 ; s = -3 -> -5
5981 v = 4 ; s = -3 -> -7
5982
5983 dif: s - v
5984 [-3 - 2] -5 (apply)
5985 [-3 - 4] -7 (apply)
5986
5987 -- left TO right
5988 v = -2 ; s = 3 -> 5
5989 v = -4 ; s = 3 -> 7
5990
5991 dif: s - v
5992 [3 - -2] 5 (apply)
5993 [3 - -4] 7 (apply)
5994
5995 equation:
5996 [dif] x = s - v
5997 if (s neg AND s > v) OR (s pos AND s < v)
5998 x = 0
5999 f = toForce(x)
6000 body->applyForce(f)
6001--]]
6002
6003local function halt(self, dt)
6004 local m = self.body:getMass()
6005 local vx, _ = self.body:getLinearVelocity()
6006 local v = -vx + vx * self.deacceleration
6007 local a = v/dt
6008 local f = a*m
6009 self.body:applyForce(f, 0)
6010end
6011
6012------------------------------ Constructor ------------------------------
6013local Mob = class("Mob", Entity) --TODO: refactor out into IWalk, IJump
6014function Mob:init(id, x, y)
6015 Entity.init(self, id, x, y)
6016 self.state = MultiState()
6017 self.dir = Mob.RIGHT
6018 self.jumpsRemaining = self.totalJumps
6019 self.extraJumps = 0
6020end
6021
6022------------------------------ Constants ------------------------------
6023Mob.LEFT = -1
6024Mob.RIGHT = 1
6025Mob.HALT = 0
6026
6027Mob.MOTIONLESS, Mob.MOVING,
6028Mob.CRAWLING, Mob.WALKING,
6029Mob.AIRBORNE, Mob.JUMPING,
6030Mob.FLYING, Mob.CLIMBING = MultiState:create()
6031
6032------------------------------ Main Methods ------------------------------
6033function Mob:tick(dt)
6034 local vx, vy = self.body:getLinearVelocity()
6035
6036 ---If mob collides with a ceiling while jumping, vy
6037 --will equal 0 for one tick; rely on Jumping as a form
6038 --of 'previous_vy' to differentiate that from landing.
6039 local jumping = self.state:is(Mob.JUMPING)
6040 local air = vy ~= 0 or jumping
6041 ---If airborne state changed:
6042 if self.state:set(Mob.AIRBORNE, air) then
6043 --From true to false; aka just landed: recharge
6044 if not air then self.jumpsRemaining = self.totalJumps end
6045 --From false to true and NOT jumping; aka slipped: lose 1 jump
6046 if air and not jumping then self.jumpsRemaining = self.jumpsRemaining - 1 end
6047 end
6048 if vy > 0 then self.state:unset(Mob.JUMPING) end
6049
6050 ---If moving at all:
6051 if vx == 0 then self.state:set(Mob.MOTIONLESS)
6052 else self.state:set(Mob.MOVING) end
6053
6054 ---If actively walking: Mob.WALKING is set if child calls _walk with dir ~= 0
6055 self.state:unset(Mob.WALKING)
6056end
6057
6058------------------------------ Walk Methods ------------------------------
6059function Mob:_walk(dir, sprint, dt)
6060 if dir ~= Mob.HALT then --TODO: Implement sprinting.
6061 self.dir = dir
6062 self.state:set(Mob.WALKING)
6063 move(self, self.speed * dir, nil, dt)
6064 else
6065 if self.state:isnot(Mob.AIRBORNE) then halt(self, dt) end
6066 self.state:unset(Mob.WALKING)
6067 end
6068end
6069
6070------------------------------ Jump Methods ------------------------------
6071--- Sets the mob's velocity and JUMPING state. Does not check any conditions.
6072function Mob:_setJumpingVelocity()
6073 self.state:set(Mob.JUMPING)
6074 local vx, vy = self.body:getLinearVelocity()
6075 vy = self.jumpHeight * -7.5 --TODO: Use proper equation/curve.
6076 self.body:setLinearVelocity(vx, vy)
6077end
6078
6079--- Checks if the mob can jump, and if so, calls self:_setJumpingVelocity() to jump.
6080function Mob:_jump()
6081 if self.jumpsRemaining == 0 and self.extraJumps > 0 then
6082 self.jumpsRemaining = self.jumpsRemaining + 1
6083 self.extraJumps = self.extraJumps - 1
6084 end
6085 if self.jumpsRemaining > 0 then
6086 self.jumpsRemaining = self.jumpsRemaining - 1
6087 self:_setJumpingVelocity()
6088 end
6089end
6090
6091------------------------------ Getters ------------------------------
6092function Mob:getDir() return self.dir end
6093
6094return Mob
6095
6096
6097
6098/////////////////Exiting file: Mob.lua/////////////////
6099//--------------------------------------------------------------------------------------------------------
6100/////////////////Entering file: Player.lua/////////////////
6101local class = require "libs.cruxclass"
6102local Mob = require "template.Mob"
6103local IHealth = require "behavior.IHealth"
6104local IMeleeAttack = require "behavior.IMeleeAttack"
6105
6106local MeleeWeapon = require "template.MeleeWeapon"
6107local IBoundingBox = require "behavior.IBoundingBox"
6108
6109local IEventHandler = require "evsys.IEventHandler"
6110local KeypressEvent = require "evsys.input.KeypressEvent"
6111local Keybinds = require "core.Keybinds"
6112
6113--local Game = require "core.Game"
6114--local Registry = require "istats.Registry"
6115
6116
6117------------------------------ Constructor ------------------------------
6118local Player = class("Player", Mob):include(IHealth, IEventHandler, IMeleeAttack)
6119function Player:init(x, y)
6120 Mob.init(self, "player", x, y)
6121 self.weapon = MeleeWeapon("swordStone")
6122end
6123
6124
6125------------------------------ Main Methods ------------------------------
6126function Player:tick(dt)
6127 Mob.tick(self, dt)
6128 local k = love.keyboard
6129
6130 local dir = 0
6131 if k.isDown(Keybinds.LEFT) then dir = dir + Player.LEFT end
6132 if k.isDown(Keybinds.RIGHT) then dir = dir + Player.RIGHT end
6133 local sprint = k.isDown(Keybinds.SPRINT)
6134 self:_walk(dir, sprint, dt)
6135end
6136
6137function Player:draw(g)
6138 g.setColor(0, 0, 1, 1)
6139 g.polygon('fill', self.body:getWorldPoints(self.shape:getPoints()))
6140end
6141
6142------------------------------ @Callback ------------------------------
6143Player:attach(KeypressEvent, function(self, e)
6144 if e.k == Keybinds.JUMP then self:_jump() end
6145
6146 if e.k == 'g' then self.totalJumps = self.totalJumps + 1 end
6147 if e.k == 'f' then self.extraJumps = self.extraJumps + 1 end
6148 if e.k == 'x' then self:attack(self.weapon) end
6149end)
6150
6151return Player
6152
6153/////////////////Exiting file: Player.lua/////////////////
6154//--------------------------------------------------------------------------------------------------------
6155/////////////////Entering file: Thing.lua/////////////////
6156local class = require "libs.cruxclass"
6157local Registry = require "istats.Registry"
6158
6159------------------------------ Constructor ------------------------------
6160local Thing = class("Thing")
6161function Thing:init(id)
6162 self.id = id
6163 Registry:apply(id, self)
6164end
6165
6166------------------------------ Abstract Methods ------------------------------
6167function Thing:draw(g) error "Abstract method Thing:draw(g) must be implemented in child!" end
6168
6169------------------------------ Getters ------------------------------
6170function Thing:getId() return self.id end
6171
6172------------------------------ Registry Getters ------------------------------
6173function Thing:getName() return Registry:getName(self.id) end
6174function Thing:getDesc() return Registry:getDesc(self.id) end
6175
6176function Thing:idEquals(o)
6177 return type(o) == 'table' and self.id == o.id
6178end
6179
6180function Thing:__tostring()
6181 return string.format("[%s:%s]",
6182 self.class.__name__, self.id)
6183end
6184
6185return Thing
6186
6187
6188/////////////////Exiting file: Thing.lua/////////////////
6189//--------------------------------------------------------------------------------------------------------
6190/////////////////Entering file: WeaponDef.lua/////////////////
6191local class = require "libs.cruxclass"
6192
6193------------------------------ Constructor ------------------------------
6194local WeaponDef = class("WeaponDef")
6195function WeaponDef:init()
6196 error "Attempting to initialize static class."
6197end
6198
6199------------------------------ Constants ------------------------------
6200WeaponDef.anchors = {}
6201WeaponDef.anchors.ORIGIN = 0
6202WeaponDef.anchors.CENTER = 1
6203WeaponDef.anchors.NATURAL = 2
6204
6205WeaponDef.transitions = {}
6206WeaponDef.transitions.INSTANT = 10
6207WeaponDef.transitions.LINEAR_GROW = 11
6208return WeaponDef
6209
6210/////////////////Exiting file: WeaponDef.lua/////////////////
6211//--------------------------------------------------------------------------------------------------------
6212/////////////////Entering file: WorldObj.lua/////////////////
6213local class = require "libs.cruxclass"
6214local Thing = require "template.Thing"
6215local IBoundingBox = require "behavior.IBoundingBox"
6216
6217local Game = require "core.Game"
6218--local Registry = require "istats.Registry"
6219
6220local EShapes = require "behavior.EShapes"
6221
6222local WorldObj = class("WorldObj", Thing):include(IBoundingBox)
6223function WorldObj:init(id, x, y, bodyType, angle)
6224 Thing.init(self, id)
6225 --TODO: Default to spr:getW/H/R() if no explicit w/h/r is provided.
6226 --TODO: Rename 'getShapeDat' to something more appropriate. Also, more abstract, to work with w/h, r, and/or others).
6227 local a, b = self:getShapeA(), self:getShapeB()
6228 IBoundingBox.init(self, Game:getLoadedWorld(), x, y, self,
6229 bodyType, self:getBodyDensity(), self:getBodyMass(),
6230 self:getBodyFriction(), self:getBodyRestitution(),
6231 self:getShapeType(), a, b, angle)
6232 self:setFixedRotation(true)
6233end
6234
6235return WorldObj
6236
6237/////////////////Exiting file: WorldObj.lua/////////////////
6238//--------------------------------------------------------------------------------------------------------
6239/////////////////Entering file: Zombie.lua/////////////////
6240local class = require "libs.cruxclass"
6241local Mob = require "template.Mob"
6242local IHealth = require "behavior.IHealth"
6243local IHittable = require "behavior.IHittable"
6244local IBoundingBox = require "behavior.IBoundingBox"
6245
6246local Game = require "core.Game"
6247--local Registry = require "istats.Registry"
6248
6249------------------------------ Helper Methods ------------------------------
6250
6251local function repath(self, f)
6252 local obj = f:getUserData()
6253 if obj:getId() ~= "player" then return true
6254 else
6255 local x, y = self:getPos()
6256 local px, py = obj:getPos()
6257
6258 if px < x then self.path = Mob.LEFT
6259 elseif x < px then self.path = Mob.RIGHT
6260 else self.path = Mob.HLT end
6261
6262 if py < y then self:_jump() end
6263
6264 return false
6265 end
6266end
6267
6268------------------------------ Constructor ------------------------------
6269local Zombie = class("Zombie", Mob):include(IHealth, IHittable)
6270function Zombie:init(x, y)
6271 Mob.init(self, "mobZombie", x, y)
6272 self.path = Mob.LEFT
6273end
6274
6275------------------------------ Main Methods ------------------------------
6276function Zombie:tick(dt)
6277 Mob.tick(self, dt)
6278 local vx, vy = self.body:getLinearVelocity()
6279-- if vx == 0 then repath(self) end
6280 local wx, wy = 32 * Game.GRID, 32 * Game.GRID
6281
6282 Game.world:queryBoundingBox(0, 0, wx, wy, function(f) return repath(self, f) end)
6283 self:_walk(self.path, false, dt)
6284
6285-- self:hurt(0.2)
6286-- print(self:getHealth())
6287end
6288
6289function Zombie:draw(g)
6290 g.setColor(0, 0.25, 0, 1)
6291 g.polygon('fill', self.body:getWorldPoints(self.shape:getPoints()))
6292
6293 local health, healthMax = self:getHealth(), self:getMaxHealth()
6294 local x, y, w, h = self:getX(), self:getY(), self:getW(), self:getH()
6295 x = x + 0.1
6296 y = y - 0.2
6297 w = (w - 0.2) * utils.map(health, 0, healthMax, 0, 1)
6298 h = 0.15
6299
6300 local r, gr, b, a = 1, 1, 0, 1
6301 r = utils.map(health, 0, healthMax, 1, 0)
6302 gr = utils.map(health, 0, healthMax, 0, 1)
6303
6304 g.setColor(r, gr, b, a)
6305 g.rectangle('fill', x, y, w, h)
6306end
6307
6308return Zombie
6309
6310/////////////////Exiting file: Zombie.lua/////////////////
6311//--------------------------------------------------------------------------------------------------------
6312/////////////////Entering file: ClassTemplate.lua/////////////////
6313============================== Obj + Super ==============================
6314local class = require "libs.cruxclass"
6315local Super = require "x"
6316
6317------------------------------ Helper Methods ------------------------------
6318
6319------------------------------ Constructor ------------------------------
6320local Object = class("Unnamed", Super)
6321function Object:init()
6322 Super.init(self)
6323end
6324
6325------------------------------ Getters / Setters ------------------------------
6326
6327return Object
6328
6329============================== Obj ==============================
6330local class = require "libs.cruxclass"
6331
6332------------------------------ Helper Methods ------------------------------
6333
6334------------------------------ Constructor ------------------------------
6335local Object = class("Unnamed")
6336function Object:init()
6337end
6338
6339------------------------------ Getters / Setters ------------------------------
6340
6341return Object
6342
6343============================== Obj + Thing ==============================
6344local class = require "libs.cruxclass"
6345local Thing = require "template.Thing"
6346
6347------------------------------ Helper Methods ------------------------------
6348
6349------------------------------ Constructor ------------------------------
6350local Object = class("Unnamed", Thing)
6351function Object:init(id)
6352 Thing.init(self, id)
6353end
6354
6355------------------------------ Getters / Setters ------------------------------
6356
6357return Object
6358
6359/////////////////Exiting file: ClassTemplate.lua/////////////////
6360//--------------------------------------------------------------------------------------------------------
6361/////////////////Entering file: FilepathUtils.lua/////////////////
6362local FilepathUtils = {}
6363
6364FilepathUtils.love = {}
6365FilepathUtils.love.path = {}
6366FilepathUtils.love.path.src = ""
6367FilepathUtils.love.path.saves = nil
6368
6369FilepathUtils.love.path.istatsData = FilepathUtils.love.path.src .. "/istats/data/"
6370FilepathUtils.love.path.istatsDefaults = FilepathUtils.love.path.src .. "/istats/defaults/"
6371--FilepathUtils.love.path.istatsDefaultsIdv = FilepathUtils.love.path.src .. "/istats/defaults/idv/"
6372--FilepathUtils.love.path.istatsDefaultsInstv = FilepathUtils.love.path.src .. "/istats/defaults/instv/"
6373
6374--FilepathUtils.lua = {}
6375--FilepathUtils.lua.path = {}
6376--FilepathUtils.lua.path.src = "src"
6377--FilepathUtils.lua.path.saves = nil
6378--
6379--FilepathUtils.lua.path.istatsData = FilepathUtils.lua.path.src .. "/istats/data/"
6380
6381return FilepathUtils
6382
6383/////////////////Exiting file: FilepathUtils.lua/////////////////
6384//--------------------------------------------------------------------------------------------------------
6385/////////////////Entering file: Scheduler.lua/////////////////
6386local class = require "libs.cruxclass"
6387
6388------------------------------ Helper Methods ------------------------------
6389local getTime = love.timer.getTime
6390local ins = table.insert
6391local rem = table.remove
6392local modf = math.modf
6393local floor = math.floor
6394
6395local function findIndex(t, obj)
6396 for k, v in ipairs(t) do
6397 if obj == v then return k end
6398 end
6399 return false
6400end
6401
6402local function execute(t, dt, i, interval, timeout, func, args)
6403 args = type(args) == 'table' and args or {args}
6404 if dt then
6405 t.tdt[i] = t.tdt[i] + dt
6406 local r = interval == -1 and 0 or interval
6407 local per = math.min(t.tdt[i] / (timeout - r), 1)
6408 func(dt, per, unpack(args))
6409 else func(unpack(args)) end
6410end
6411
6412local function remove(t, i)
6413 rem(t.wait, i)
6414 rem(t.interval, i)
6415 rem(t.timeout, i)
6416 rem(t.stamp, i)
6417 rem(t.tdt, i)
6418 rem(t.flag, i)
6419 rem(t.last, i)
6420 rem(t.runs, i)
6421 rem(t.func, i)
6422 rem(t.args, i)
6423 rem(t.wrapup, i)
6424 rem(t.wargs, i)
6425end
6426
6427local function yield(t, i)
6428 if t.wrapup[i] then execute(nil, nil, nil, nil, nil, t.wrapup[i], t.wargs[i]) end
6429 remove(t, i)
6430end
6431
6432local function process(t, dt, i, wait, interval, timeout, stamp, flag, last, runs, func, args)
6433 local time = getTime()
6434
6435 if time >= stamp + wait then --If (at or post 'wait'); proceed
6436 if interval == 0 then -- If 'interval' == 0; single execution
6437 local dt = time - stamp --
6438 execute(t, dt, i, interval, timeout, func, args) -- Execute once; 'fdt' = time since initial scheduling
6439 return true -- Yield
6440 elseif timeout == 0 or time <= stamp + timeout then -- If (no timeout is set) or (within timeout); proceed
6441 if interval == -1 then -- If interval == -1; execute every tick
6442 local fdt = flag == 0 and dt or time - stamp -- 'fdt' = (first run) ? tick-dt : time since initial scheduling
6443 t.flag[i] = 0 -- Set 'first run' flag
6444 execute(t, fdt, i, interval, timeout, func, args)-- Execute
6445 else -- If 'interval' set (not 0 and not -1); execute every 'interval' for 'timeout'
6446 local fdt, dif, reruns -- [1]elaborated below
6447 if flag == -1 then --
6448 fdt = time - stamp --
6449 dif = time - stamp - wait --
6450 else --
6451 fdt = time - last --
6452 dif = time - flag --
6453 end --
6454 --
6455 reruns = floor(dif / interval) --
6456 dif = dif % interval --
6457 if flag == -1 then reruns = reruns + 1 end --
6458 --
6459-- print('dt', dt, 'fdt', fdt, 'dif', dif, 'flag', flag, 'reruns', reruns, 'interval', interval)
6460 for _i = 1, reruns do --
6461 execute(t, _i == 1 and fdt or 0, i, interval, timeout, func, args)
6462 t.runs[i] = t.runs[i] + 1 --
6463-- if i == reruns then flag = time end --
6464 if _i == reruns then --
6465 dif = 0 --
6466 t.last[i] = time --
6467 t.flag[i] = time - dif --
6468 end --
6469 end --
6470-- print('dt', dt, 'fdt', fdt, 'dif', dif, 'flag', flag, 'reruns', reruns, 'interval', interval)
6471 end --
6472 else --
6473 if last ~= -1 then --
6474 for _ = 1, (timeout / interval) - runs do --
6475 execute(t, 0, i, interval, timeout, func, args)
6476 end --
6477 end --
6478 return true --
6479 end -- If timed out; yield
6480 end
6481end
6482
6483--[[
6484Execution:
6485once at or post 'wait':
6486 if interval == 0 -> execute then remove; //dt equals time - stamp
6487 elseif interval == -1
6488 if timeout == 0 or within timeout, execute; //dt if first time equals time - stamp
6489 else remove; //else equals tick dt
6490 (repeat the above 'if' once every tick)
6491 else;
6492 execute every INTERVAL for TIMEOUT ;
6493 if ticks took longer than INTERVAL -> execute multiple times per tick
6494 [1][elaborated below]
6495
6496[1]
6497if timed out; yield
6498if flag == -1
6499 fdt = time - stamp
6500 dif = time - stamp - wait
6501else
6502 fdt = time - last
6503 dif = time - flag
6504
6505reruns = floor(dif / interval)
6506dif = dif % interval
6507
6508if flag == -1 then reruns++ end
6509
6510for i = 1, reruns do
6511 execute(i == 1 and fdt or 0) --if multiple executions in a row, the first is passed dt the rest are passed 0
6512 if i + 1 == reruns then flag = time end
6513end
6514last = flag
6515flag = flag - dif
6516
6517[2] examples !!! outdated !!!
6518stamp = 30
6519wait = 5
6520interval = 1
6521flag = -1
6522
6523------------ first run [time = 35.3] //since stamp = 5.3 ; since first run 0.3
6524fdt = 5.3
6525dif = 0.3
6526 reruns, dif = 0++, 0.3 [0.3 / 1 ; ++]
6527
6528flag = 35.0
6529
6530------------ second run [time = 36.8] //since stamp = 6.8 ; since first run 1.8
6531fdt = 1.8
6532dif 1.8
6533 reruns, dif = 1, 0.8 [1.8 / 1]
6534
6535flag = 36.0
6536
6537------------ third run [time = 38.3] //since stamp = 8.3 ; since first run 3.3
6538fdt = 1.8
6539dif = 2.3
6540 reruns, dif = 2, 0.3 [2.3 / 1]
6541
6542flag = 38.0
6543
6544------------ fourth run [time = 39.8] //since stamp = 9.8 ; since first run 4.8
6545fdt = 1.8
6546dif 1.8
6547 reruns, dif = 1, 0.8 [1.8 / 1]
6548
6549flag = 39.0
6550--]]
6551------------------------------ Constructor ------------------------------
6552local Scheduler = class("Scheduler")
6553function Scheduler:init()
6554 self.tasks = {wait = {}, interval = {}, timeout = {}, stamp = {}, tdt = {},
6555 flag = {}, last = {}, runs = {}, func = {}, args = {}, wrapup = {}, wargs = {}}
6556
6557 self.gtasks = {wait = {}, interval = {}, timeout = {}, stamp = {}, tdt = {},
6558 flag = {}, last = {}, runs = {}, func = {}, args = {}, wrapup = {}, wargs = {}}
6559end
6560
6561------------------------------ Main Methods ------------------------------
6562--TODO: pass graphical tasks a 'g' param in place of 'dt'.
6563local function processAll(t, dt)
6564 local yielded = {}
6565 for i = 1, #t.func do --All subtables of self.tasks should always be of equal length.
6566 local done = process(t, dt, i, t.wait[i], t.interval[i], t.timeout[i], t.stamp[i],
6567 t.flag[i], t.last[i], t.runs[i], t.func[i], t.args[i])
6568 if done then ins(yielded, i) end
6569 end
6570
6571 for i = 1, #yielded do --Remove yielded entries in reverse order (so indices remain consistent during yielding)
6572 yield(t, yielded[#yielded + 1 - i])
6573 end
6574end
6575
6576function Scheduler:tick(dt)
6577 processAll(self.tasks, dt)
6578end
6579
6580local gPrevTime = 0, getTime()
6581function Scheduler:draw(g)
6582 local dt = getTime() - gPrevTime
6583 processAll(self.gtasks, dt)
6584 gPrevTime = getTime()
6585end
6586
6587------------------------------ Schedule Method ------------------------------
6588function Scheduler:schedule(wait, interval, timeout, stamp, func, args, wrapup, wargs, graphical)
6589 local t = graphical and self.gtasks or self.tasks
6590 ins(t.wait, wait or 0)
6591 ins(t.interval, interval or 0)
6592 ins(t.timeout, timeout or 0)
6593 ins(t.stamp, stamp or getTime())
6594 ins(t.tdt, 0)
6595 ins(t.flag, -1)
6596 ins(t.last, -1)
6597 ins(t.runs, 0)
6598 ins(t.func, func)
6599 ins(t.args, args or {})
6600 ins(t.wrapup, wrapup)
6601 ins(t.wargs, wargs or {})
6602end
6603
6604------------------------------ Schedule Shortcuts ------------------------------
6605function Scheduler:callAfter(wait, func, args, wrapup, wargs)
6606 self:schedule(wait, nil, nil, nil, func, args, wrapup, wargs)
6607end
6608
6609function Scheduler:callFor(timeout, func, args, wrapup, wargs)
6610 self:schedule(nil, -1, timeout, nil, func, args, wrapup, wargs)
6611end
6612
6613function Scheduler:callEvery(interval, func, args, wrapup, wargs)
6614 self:schedule(nil, interval, nil, nil, func, args, wrapup, wargs)
6615end
6616
6617function Scheduler:callEveryFor(interval, timeout, func, args, wrapup, wargs)
6618 self:schedule(nil, interval, timeout, nil, func, args, wrapup, wargs)
6619end
6620
6621------------------------------ Schedule Graphical Shortcuts ------------------------------
6622function Scheduler:gCallAfter(wait, func, args, wrapup, wargs)
6623 self:schedule(wait, nil, nil, nil, func, args, wrapup, wargs, true)
6624end
6625
6626function Scheduler:gCallFor(timeout, func, args, wrapup, wargs)
6627 self:schedule(nil, -1, timeout, nil, func, args, wrapup, wargs, true)
6628end
6629
6630function Scheduler:gCallEvery(interval, func, args, wrapup, wargs)
6631 self:schedule(nil, interval, nil, nil, func, args, wrapup, wargs, true)
6632end
6633
6634function Scheduler:gCallEveryFor(interval, timeout, func, args, wrapup, wargs)
6635 self:schedule(nil, interval, timeout, nil, func, args, wrapup, wargs, true)
6636end
6637------------------------------ Cancel Methods ------------------------------
6638function Scheduler:cancel(func)
6639 local i = type(func) == 'number' and func or findIndex(self.tasks.func, func)
6640 if i then remove(self.tasks, i) end
6641 --Graphical tasks:
6642 i = type(func) == 'number' and func or findIndex(self.gtasks.func, func)
6643 if i then remove(self.gtasks, i) end
6644end
6645
6646function Scheduler:cancelAll()
6647 for i = 1, self.tasks.func do
6648 remove(self.tasks, i)
6649 end
6650 --Graphical tasks:
6651 for i = 1, self.gtasks.func do
6652 remove(self.gtasks, i)
6653 end
6654end
6655------------------------------ Yield Methods ------------------------------
6656function Scheduler:yield(func)
6657 local i = type(func) == 'number' and func or findIndex(self.tasks.func, func)
6658 if i then yield(self.tasks, i) end
6659 --Graphical tasks:
6660 i = type(func) == 'number' and func or findIndex(self.gtasks.func, func)
6661 if i then yield(self.gtasks, i) end
6662end
6663
6664function Scheduler:yieldAll()
6665 for i = 1, self.tasks.func do
6666 yield(self.tasks, i)
6667 end
6668 --Graphical tasks:
6669 for i = 1, self.gtasks.func do
6670 yield(self.gtasks, i)
6671 end
6672end
6673
6674return Scheduler()
6675
6676
6677/////////////////Exiting file: Scheduler.lua/////////////////
6678//--------------------------------------------------------------------------------------------------------
6679/////////////////Entering file: Timer.lua/////////////////
6680local class = require "libs.cruxclass"
6681
6682local Timer = class("Timer")
6683function Timer:init()
6684 self.funcs, self.times, self.cleanup = {}, {}, {}
6685end
6686
6687function Timer:tick(dt)
6688 if #self.funcs > 0 then
6689 for k, f in ipairs(self.funcs) do
6690 self.times[k] = self.times[k] - dt
6691 if self.times[k] <= 0 then
6692 self.cleanup[k]()
6693 table.remove(self.funcs, k)
6694 table.remove(self.times, k)
6695 table.remove(self.cleanup, k)
6696 else f() end
6697 end
6698 end
6699end
6700
6701function Timer:callFor(obj, sec, func, cleanup)
6702 local i = false;
6703 for k, v in ipairs(self.funcs) do
6704 if v == func then i = k end
6705 end
6706 if not i then
6707 table.insert(self.funcs, func)
6708 table.insert(self.times, sec)
6709 table.insert(self.cleanup, cleanup or function() end)
6710 end
6711end
6712
6713return Timer
6714
6715/////////////////Exiting file: Timer.lua/////////////////
6716//--------------------------------------------------------------------------------------------------------