0,]']>S}Wup8d%qy;]AsVl3333333333333>33333333333333C4ffffffffofffffffffffofffffff>DDDDDDDDDDDD?ddDDDDDDDDDDCDC4fffffffDDDDDDDDffffffffffDDDDDDDDfffffffϬLDDDODDD?DfDDDDODDDCDC4ffffODoffffODoffff̪HODDDDD4C$3BODDDDD4CDC4ffffODDDDDDDffffODDDDDDDffff̌DDODODDD4C$3DODODDD4CD33ffffODDDDDDUeffODDDDDDffff?DHDDOODDDDD>D$3DOODDDDD܍CDC4ffffODDDDDDDDffffODDDDDDDDffff?DDDODDDD>D$#HODDDDCDC4ffffODDDODDDDffffODDDODDDDffffCDDDDDDDDDDDDDD4CD$DDDDDDDDDDD4CDC4ffffODDDDDDDDDDDDDDffffODDDDDDDDDDDDDDffffCDDDDDDDDDDDDDD4CDDHDDDDDDDDDDD433C4ffffffffffffw3333333333333333wwwwwww3333333333333333wwwwwwwwwwwwwCDC4ffffffffffffw""""""""""""""""wwwwwww""""""""""""""""wwwwwwwwwwwwwCDC4ffffffffffffw""""""""""""""""wwwwwww""""""""""""""""wwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffff˛ffffffff˛ffff""""""""""""""""wwwxwww""""""""""""""""wwwwwwww7333333333swwwwCD33fffffl̿fffffl̿ffffw"33333333333333"wwwwwww"33333333333333"wwwwwwwwCDDDDDDD4wwwwCDC4fVVffllfϛfVVffllfϛfVVfw"33333333333333"wwwwwww"33333333333333"wwwwwww7DDDHDHDswwwCDC4ffefff̿ffefff̿ffefw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwwwCDDDDDD4wwwCDC4ffffffll̟ffffffll̟iffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwww7DDDHDDDDsww33C4ffffff̟ʬffffff̟2#ffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwwCDDDDDDDDDDDDDD4wwCDC4ffffffff̟ʬffffffff̟2#ffffw"3"""""2#"""""3"wwwwxww"3"""""2#"""""3"wwwww3333333333333333wwCDC4fffflf̟̘fffff̟2#ffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwww7DDswwwwwwCD4wwwwCDC4fffff̟Ɍfffff̟2ffffw"3"""3"2#"3"""3"wwwwwww"3"""3"2#"3"""3"wwwww7DDswwwwwCD4wwwwCD33fffffl̟ffffl̟"ffffw"3"""3"2#"3"""3"wwwwwww"3"""3"2#"3"""3"wwwwwww7DDswwwwwwCD4wwwwCDC4fffff̟fffff̟ffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwww7DDswwwwwwCD4wwwwCDC4ffffll̟ffffll̟ffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwww7DDswwwwwwCD4wwwwCDC4ffffffff̟ffffffff̟ffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwww7DDswwwwwwCD4wwww33C4ffffffffffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwww7DD3333333CD4wwwwCDC4ffffffffffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwwww7DDswwwwwwCD4wwwwCDC4ffffffffffffw"3"""""2#"""""3"wwwwwww"3"""""2#"""""3"wwwwxww7D4wwwwwww7D4xwwwCDC4ffffof/"""offffffffffffof/"""offffffffffffw"33333333333333"wwwwwww"33333333333333"wwwwwww7DswwwwwwwwC4wwwwCD33ffffofoffffffffffffofoffffffffffffw"33333333333333"wwwwwww"33333333333333"wwwwwww74wwwwwwwww74wwwwCDC4fVVfo""""ffffffffffffo""""fffffffffVVfw""""""""""""""""wwwwwww""""""""""""""""wwwwwww7swwwwwwwwww3wwwwCDC4ffefo""""ffffffffffffo""""ffffffffffefw""""""""""""""""wwwwwww""""""""""""""""wwwwwww7wwwwwwwwwww7wwwwCDC4ffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww33C4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwxwwxwwwwwwwwwwwwwwxwwwwwwwwwwwwwwxwwwwwwwwwwwwwwxwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwww""""""wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwww""""""wwwwwwwwwwwwwwwwwwwwwwwwwwwwwCD33ffffUeffffffUeffffffUeffffffUeffffffUeffffffwwwwwwwwwwwwwwwwwwwwwww""""""""wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwww""""""""wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwww"""""DwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwww"""""Dwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww3333ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwww""""DDDDDwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwww""""DDDDDwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwxwwwww""wwDDDDDwxwwwwwwwwwwwwwwwxwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwww""wwDDDDDwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwww""wwwDDDDDwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""fffffVVffffffVVffffffVVffffffVVffffffVVfwwwwwwwwwwwwwwwwwwwww""wwwDDDDDwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffefffffffefffffffefffffffefffffffefwwwwwwwwwwwwwwwwwwwww"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwww"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffw""""wwwwwwwwwwwxwwwwwwxwwwwwwwwwwwwwwwxwwwwwwwwwww"""/""UeffffffUeffffffUeffffffUeffffffUeffffffw/3333wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffw/3333wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffw""""wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffw""""wwwwwwwwwwwxwwwwwwwwwwxwwwwwwwwwwwwwwxwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffw/3333wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffw/3333߇wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffw""""wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""fffffVVffffffVVffffffVVffffffVVffffffVVfwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffefffffffefffffffefffffffefffffffefwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwxwwwwwwwwwwwwwwwxwwwwwwwwwwwwwwwxwwwwwwwwwwwwwwwxwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""UeffffffUeffffffUeffffffUeffffffUeffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"""/""ffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww3333ffffffffffffffffffffffffffffffffffffffffffffwxwwwwwwwwwwwwwwxwwwwwwwwwwwwwwxwwwwwwwwwwwwwwxwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCD33ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4fVVffffffVVffffffVVffffffVVffffffVVffffffVVfwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffefffffffefffffffefffffffefffffffefffffffefwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww33C4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwxwwwwwwwwwwwxwwwwwwwwwwwwwwwxwwwwwwwwwwwwwwwxwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCD33ffffUeffffffUeffffffUeffffffUeffffffUeffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww33C4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwxwwwwwwwwwwwwwwxwwwwwwwwwwwwwwxwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCD33ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4fVVffffffVVffffffVVffffffVVffffffVVffffffVVfwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwCDC4ffefffffffefffffffefffffffefffffffefffffffefwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwDDDxwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwHDDDwwwwwwwwwwwwwww33C4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwDLDxwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwDLDxwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwxwwwwwwwwwwwwwwwxwwwwwwwwwwwwwwwxwwDDDDDxwwwwwwxwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwHDDDwwwwwwwwwwwwwwwCD33ffffUeffffffUeffffffUeffffffUeffffffUeffffffwwwpwwwwwwwww3333333333333333wwwwwwwDDDxwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwpwwwwwwwCDDDDDDDDDDDDDD4wwwwwwwHDDDwwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwpwwwwwwwCDDDDDDDDDDDDDD4wwwwwwDDDDDxwwwwwwwwwwwwwwCDC4ffffffffffffffffffffffffffffffffffffffffffffwwwpwwwwwwwCDDDDDDDDDDDDDD4wwwwwwHDDDDDwwwwwwwwwwwwww33C4ffffffffffffffffffffffffffffffffffffffffffffCDDDDDDDDDDDDDD4ȬʌCDC4ffffffffffffffffffffffffffffffffffffffffffffCDDDDDDDDDDDDDD4H̪CDC4ffffffffffffffffffffffffffffffffffffffffffff3DDDDDDDDDDDDDD3HLCDC4ffffffffffffffffffffffffffffffffffffffffffff?DDDDDDDDDDDDDDHHCD33ffffffffffffffffffffffffffffffffffffffffffff?DDDDDDDDDDDDDDCDC4fVVffffffVVffffffVVffffffVVffffffVVffffffVVf?DDDDDDDDDDDDDDCDC4ffefffffffefffffffefffffffefffffffefffffffef?CDDDDDDDDDDDD4CDC4ffffffffffffffffffffffffffffffffffffffffffffCDDDDDDDDDDDD433C4ffffffffffffffffffffffffffffffffffffffffffffCDDDDDDDDDDDD4CDC4ffffffffffffffffffffffffffffffffffffffffffffCDDDDDDDDDDDD4CDC4ffffffffffffffffffffffffffffffffffffffffffffCDDDDDDDDDDDD4CDC4ffffffffffffffffffffffffffffffffffffffffffff3DDDDDDDDDDDD3CD33ffffUeffffffUeffffffUeffffffUeffffffUeffffff>DDDDDDDDDDDDCDC4ffffffffffffffffffffffffffffffffffffffffffff>DDDDDDDDDDDDCDC4ffffffffffffffffffffffffffffffffffffffffffff>333333333333CDC4ffffffffffffffffffffffffffffffffffffffffffff3333ffffffffffffffffffffffffffffffffffffffffffffY-- title: Baby Simulator -- author: xmonkee -- desc: Keep the baby happy. Baby needs food, play and clean diapers. -- license: MIT License (change this to your license of choice) -- version: 0.1 -- script: lua Menu = {} Menu.__index = Menu function Menu.new(self, actions) -- modes = shown | selected | started -- shown + z -> selected -- selected + x -> shown -- selected + z -> started -- started + z(hold) -> progressing -- progressing == 100 = action() -> selected -- for single item -- shown + z -> started local o = { actions=actions or {}, selected=1, mode="shown", progress=0, waitRelease=false } setmetatable(o, self) return o end function Menu.empty(self) self.actions={} self.selected=1 self.mode="shown" self.progress=0 end function Menu.add(self, action) table.insert(self.actions, action) end function Menu.incSel(self) self.selected = math.min(#self.actions, self.selected + 1) self.mode = "selected" self.progress=0 end function Menu.decSel(self) self.selected = math.max(1, self.selected - 1) self.mode = "selected" self.progress=0 end function Menu.drawLabel(self,label,x,y,selected) local color = colors.menuItem local w,h = 70,8 if selected then rect(x,y,w+1,h+1,0) rect(x-1,y-1,w,h,colors.menuItemSelected) rect(x-1,y-1,w/100*self.progress,h,colors.menuItemProgress) print(label, x,y,colors.menuItemText, false, 1, true) else rect(x,y,w,h,color) print(label, x+1,y+1,colors.menuItemText, false, 1, true) end end function Menu.draw(self) local x=max(5,min(players.parent.loc.x,168)) local ys=players.parent.loc.y-(#self.actions*8)-2 if ys < 20 then ys=players.parent.loc.y+players.parent.loc.h*players.parent.loc.sc*8+2 end for i,action in pairs(self.actions) do local y=ys+(i-1)*9 self:drawLabel(action.label,x,y,self.mode ~= "shown" and self.selected==i) end end function Menu.handleKeys(self) -- return boolean indicating if caller can process other keystrokes if self.waitRelease then if not btn(4) then self.waitRelease = false else return true end end if self.mode == "shown" and btn(4) then self.mode = "selected" elseif self.mode == "selected" then if btnp(4,10,0) then self.mode = "started" end if btnp(0) then self:decSel() end if btnp(1) then self:incSel() end if btnp(2) or btnp(3) or btnp(5) then self.mode = "shown" end elseif self.mode == "started" then if self.progress >= 100 then sfx(32,"C-4",30,2,15,0) self.actions[self.selected].fn() self.progress = 0 self.mode = "selected" self.waitRelease=true s.recalcTrigs = true else if btnp(0) then self:decSel() end if btnp(1) then self:incSel() end if btn(2) or btn(3) or btn(5) then self.mode = "selected" self.progress = 0 end if btn(4) then self.progress = self.progress+self.actions[self.selected].rate/ticsPerMin*60*3 end end end return self.mode == "shown" or #self.actions == 1 end PALETTE_MAP = 0x3FF0 RED = 3 SOLIDS = {[73]=1,[74]=1,[75]=1} -- "solid" map sprites min = math.min max = math.max function solid(x,y) return SOLIDS[mget(x//8,y//8)] end Obj = {} Obj.__index = Obj function Obj:new(loc) loc.zero = loc.zero or 0 local obj = {loc=loc} setmetatable(obj, self) return obj end function Obj:fullBloc() local loc = self.loc return { x1=loc.x, y1=loc.y, x2=loc.x+loc.w*8*loc.sc, y2=loc.y+loc.h*8*loc.sc } end function Obj:calcBloc() local loc = self.loc return { x1=loc.x+(loc.lf or 0)*loc.sc, y1=loc.y+(loc.up or 0)*loc.sc, x2=loc.x+(loc.rt or loc.w*8)*loc.sc, y2=loc.y+(loc.dn or loc.h*8)*loc.sc } end function Obj:draw(active) local loc = self.loc if active then withSwapAll(12, function() spr(loc.spr,loc.x-1,loc.y,loc.zero,loc.sc,0,0,loc.w,loc.h) spr(loc.spr,loc.x+1,loc.y,loc.zero,loc.sc,0,0,loc.w,loc.h) spr(loc.spr,loc.x,loc.y-1,loc.zero,loc.sc,0,0,loc.w,loc.h) spr(loc.spr,loc.x,loc.y+1,loc.zero,loc.sc,0,0,loc.w,loc.h) spr(loc.spr,loc.x-1,loc.y-1,loc.zero,loc.sc,0,0,loc.w,loc.h) spr(loc.spr,loc.x+1,loc.y-1,loc.zero,loc.sc,0,0,loc.w,loc.h) spr(loc.spr,loc.x-1,loc.y+1,loc.zero,loc.sc,0,0,loc.w,loc.h) spr(loc.spr,loc.x+1,loc.y+1,loc.zero,loc.sc,0,0,loc.w,loc.h) end) end spr(loc.spr,loc.x,loc.y,loc.zero,loc.sc,0,0,loc.w,loc.h) end Player = {} Player.__index = Player setmetatable(Player, Obj) function Player:clear(obj) if collision(self:calcBloc(), obj:calcBloc()) then self.loc.y = obj.loc.y - (self.loc.dn or self.loc.h*8)*self.loc.sc end end function withFlashing(mainColor, swapWith, isFlashing, f) if isFlashing() and (t//10%2) == 0 then withSwap(mainColor, swapWith, f) else f() end end function withSwapAll(newi, f) for i = 0,15 do poke4(PALETTE_MAP*2+i, newi) end f() for i = 0,15 do poke4(PALETTE_MAP*2+i, i) end end function withSwap(i, j, f) poke4(PALETTE_MAP*2+i,j) f() poke4(PALETTE_MAP*2+i,i) end function collision(bloc1, bloc2) local left,right = bloc1,bloc2 local up,down = bloc1,bloc2 if bloc1.x1 > bloc2.x1 then left,right = right,left end if bloc1.y1 > bloc2.y1 then up,down = down,up end if left.x2 < right.x1 then return false end if up.y2 < down.y1 then return false end return true end function isAdjacent(bloc1, bloc2) -- technically adjacent OR overlapping, -- but we assume overlap is avoided elsewhere local left,right = bloc1,bloc2 local up,down = bloc1,bloc2 if bloc1.x1 > bloc2.x1 then left,right = right,left end if bloc1.y1 > bloc2.y1 then up,down = down,up end if left.x2 < right.x1-3 then return false end if up.y2 < down.y1-3 then return false end return true end function anyCollisions(bloc,playerName) for _,obj in pairs(objs) do -- objects if collision(bloc, obj:calcBloc()) then return true end end --for name,player in pairs(players) do -- players --if playerName ~= name and --collision(bloc, player:calcBloc()) then --return true --end --end if solid(bloc.x1,bloc.y1) or -- walls solid(bloc.x2,bloc.y1) or solid(bloc.x1,bloc.y2) or solid(bloc.x2,bloc.y2) then return true end if bloc.x1 < 10 or -- edges bloc.x2 > 230 or bloc.y1 < 40 or bloc.y2 > 136 then return true end return false end function Action(label, rate, fn) local action = {label=label, rate=rate, fn=fn} return action end function _triggered(self) for _, cond in pairs(self.conds) do if not cond() then return false end end return true end function Trigger(triggerArgs) local t=triggerArgs --{name, conds, action} t.triggered = _triggered return t end function drawMeter(icon,x,y,val) withFlashing(0, 1, function() return val < 20 end, function() rect(x+8,y+2,15,4,0) end) withFlashing(colors.label, RED, function() return val < 20 end, function() rect(x+9,y+3,math.ceil(val/100*13),2,colors.label) end) spr(icon,x,y,0) end function initBaby() local baby = Player:new({x=100,y=116,w=2,h=2,ospr=336,spr=336,sc=1}) baby.props = {full=50, love=50} baby.poops = 0 baby.poopedAt = 0 baby.mainColor = 4 baby.maxPoops = 3 function baby.sad(self) local p = self.props if p.full <= 0 then return "Baby got too hungry" end if p.love <= 0 then return "Baby got too sad" end if self.poops >= self.maxPoops then return "Baby got too dirty" end return false end function baby.poop(self) sfx(34,"C-4",10,3,15,0) self.poops = self.poops + 1 self.poopedAt=t end baby._draw = baby.draw -- original draw fn function baby.draw(self, isActive) self:_draw(isActive) local loc = self.loc -- Draw meters local x = 145 local y = 0 spr(263,x,y,0) -- baby face x = x + 10 print("[",x,y+1,colors.label) x = x + 4 drawMeter(handSprs.food.spr,x,y,self.props.full) x = x + 25 drawMeter(258,x,y,self.props.love) x = x + 26 print("]",x,y+1,colors.label) -- draw the poops x = loc.x+15 y = loc.y+10 for _ = 1,self.poops do spr(267,x,y,0) x = x + 8 end end function baby.updateTimeBasedStats(self) local p = self.props local TPH = ticsPerHour p.full = max(0,p.full-100/TPH) p.love = max(0,p.love-100/TPH) self:randomWalk() end function baby.fireEvents(self) if math.random() < 0.004*(t - self.poopedAt)/ticsPerHour then self:poop() notify("Baby Pooped") end end local vx, vy = 0, 0 local function setRandomDirection() vx = 2 - math.random()*4 vy = 2 - math.random()*4 end local function clear(obj) -- This is a hack so that baby is -- never int the area where garbage truck -- can show up return pbloc.x2 >= objs.trash.truck.loc.x and pbloc.y2 >= objs.trash.truck.loc.y end setRandomDirection() function baby.randomWalk(self) if isAdjacent( self:calcBloc(), players.parent:fullBloc()) then return end local l = self.loc local x,y,pbloc x=l.x+vx*math.sin(t/32) y=l.y+vy*math.cos(t/32) pbloc = {x1=x,y1=y,x2=x+16,y2=y+16} if anyCollisions(pbloc, "baby") then setRandomDirection() return else l.x = x l.y = y if (t % 120 == 0) then setRandomDirection() end end end return baby end handSprs = { diaps={spr=371,s=2}, diap={spr=260,s=1}, pdiap={spr=257,s=1}, --poop diaper groc={spr=276,s=2}, ingr={spr=370,s=1}, food={spr=270,s=1}, trash={spr=278,s=2}, } function initParent() local parent = Player:new({ x=50,y=50,ospr=304,spr=304,sc=2,w=2,h=2, flip=0,lf=6,rt=10,up=14,dn=16, vx=0,vy=0 }) function parent.fullBloc(self) local l = self.loc return {x1=l.x,y1=l.y,x2=l.x+20,y2=l.y+32} end parent.props = {enr=100, hpy=100} parent._hand = nil function parent.emptyHanded(self) return self._hand == nil end function parent.hold(self, item) self._hand = item end function parent.drop(self, item) local r = self._hand self._hand = nil return r end function parent.isHolding(self, item) return self._hand == item end function parent.handSpr(self) if self:emptyHanded() then return nil end return handSprs[self._hand] end function parent.draw(self) local l = self.loc spr(l.spr,l.x,l.y,0,l.sc,l.flip,0,l.w,l.h) local hspr = self:handSpr() if hspr then -- draw object in hand local x = l.x + 23 if l.flip==1 then x = l.x+1 end spr(hspr.spr,x,l.y+10,0,1,0,0,hspr.s,hspr.s) end x = 214 spr(269,x,0, 0) x = x + 8 print(res.money, x, 1, colors.label) end local vx, vy = 0, 0 function parent.handleKeys(self) if btn(0) then vy=max(-2,vy-.1) elseif btn(1) then vy=min(2,vy+.1) elseif vy>0.1 then vy=vy-0.1 elseif vy<-0.1 then vy=vy+0.1 else vy=0 end if btn(2) then vx=max(-2,vx-.1) elseif btn(3) then vx=min(2,vx+.1) elseif vx>0.1 then vx=vx-0.1 elseif vx<-0.1 then vx=vx+0.1 else vx=0 end if btnp(2) then self.loc.flip = 1 end if btnp(3) then self.loc.flip = 0 end if btn(0) or btn(1) or btn(2) or btn(3) then --walking animation self.loc.spr = self.loc.ospr + ((t//10)%2 + 1)*2 else self.loc.spr = self.loc.ospr end if vx == 0 and vy == 0 then return end local l = self.loc local x,y,pbloc -- Check if x is blocked x=l.x+vx y=l.y pbloc = {x1=x+l.lf*l.sc,y1=y+l.up*l.sc,x2=x+l.rt*l.sc,y2=y+l.dn*l.sc} if anyCollisions(pbloc, "parent") then vx=-vx/8 end -- small bounce -- Check if y is blocked x=l.x y=l.y+vy pbloc = {x1=x+l.lf*l.sc,y1=y+l.up*l.sc,x2=x+l.rt*l.sc,y2=y+l.dn*l.sc} if anyCollisions(pbloc, "parent") then vy=-vy/8 end -- small bounce -- Check if x AND y is blocked even if individually unblocked -- (heading into a protruding edge) x=l.x+vx y=l.y+vy pbloc = {x1=x+l.lf*l.sc,y1=y+l.up*l.sc,x2=x+l.rt*l.sc,y2=y+l.dn*l.sc} if anyCollisions(pbloc, "parent") then vx,vy=0,0 end l.x = l.x+vx l.y = l.y+vy end return parent end function initTrash() local trash = Obj:new({x=20,y=116,w=2,h=2,spr=274,sc=1}) local truck = Obj:new({x=160,y=90,w=4,h=4,spr=343,sc=2,dn=16, up=5}) trash.maxTrash = 5 trash.truck = false trash._draw = trash.draw -- original draw fn function trash.draw(self, isActive) self:_draw(isActive) local loc = self.loc -- Draw trash meter local h = math.ceil(res.trash/self.maxTrash*14) rect(loc.x-5,loc.y,4,16,0) rect(loc.x-4,loc.y+15-h,2,h,12) end function trash.fireEvents(self) if math.floor(minute) == 30 and not self.truck then self.truck=true objs.truck=truck players.parent:clear(truck) players.baby:clear(truck) notify("Garbage truck is here") end if math.floor(minute) == 40 and self.truck then self.truck=false objs.truck=nil notify("Garbage truck has left") end end return trash end function initTbl() local tbl = Obj:new({x=50,y=116,w=4,h=4,spr=412,sc=1,bt=18}) tbl.holding = nil tbl._draw = tbl.draw -- original draw fn function tbl.draw(self, isActive) self:_draw(isActive) local l = self.loc local hspr = handSprs[self.holding] if hspr then local x = l.x + 12 local y = l.y + 5 spr(hspr.spr,x,y,0,1,0,0,hspr.s,hspr.s) end end function tbl.isEmpty(self) return not self.holding end function tbl.hold(self, item) self.holding = item end function tbl.drop(self) local r = self.holding self.holding = nil return r end return tbl end function initTriggers() local emptyHand = function() return players.parent:emptyHanded() end local notEmptyHand = function() return not players.parent:emptyHanded() end local holding = function(thing) return function() return players.parent:isHolding(thing) end end triggers = {} triggers.dshelf = { Trigger{ name="takeDiap", conds={emptyHand, function() return res.diap >= 1 end}, action=Action("Take diaper", 3, function() res.diap = res.diap - 1 players.parent:hold("diap") end) }, Trigger{ name="storeDiaps", conds={holding("diaps")}, action=Action("Store diapers", 3, function() res.diap = res.diap + 3 players.parent:drop() end) }, Trigger{ name="storeDiap", conds={holding("diap")}, action=Action("Store diaper", 3, function() res.diap = res.diap + 1 players.parent:drop() end) } } triggers.gshelf = { Trigger{ name="takeIngr", conds={emptyHand,function() return res.groc >= 1 end}, action=Action("Take ingredients", 3, function() res.groc = res.groc - 1 players.parent:hold("ingr") end) }, Trigger{ name="storeGrocs", conds={holding("groc")}, action=Action("Store groceries", 3, function() res.groc = res.groc + 3 players.parent:drop() end) }, Trigger{ name="storeIngr", conds={holding("ingr")}, action=Action("Store ingredients", 3, function() res.groc = res.groc + 1 players.parent:drop() end) } } triggers.dstore = { Trigger{ name="buyDiaps", conds={emptyHand, function() return res.money >= costs.diaps end}, action=Action("Buy diapers", 3, function() players.parent:hold("diaps") res.money = res.money - costs.diaps end) } } triggers.gstore = { Trigger{ name="buyGroc", conds={emptyHand, function() return res.money >= costs.groc end}, action=Action("Buy groceries", 3, function() players.parent:hold("groc") res.money = res.money - costs.groc end) } } triggers.stove = { Trigger{ name="cook", conds={holding("ingr")}, action=Action("Cook", 2, function() players.parent:hold("food") end) } } triggers.baby = { Trigger{ name="changeDiap", conds={holding("diap"), function() return players.baby.poops >= 1 end}, action=Action("Change diaper", 2, function() players.baby.poops = 0 players.parent:hold("pdiap") end) }, Trigger{ name="play", conds={emptyHand}, action=Action("Play with baby", 2, function() players.baby.props.love=min(100, players.baby.props.love+40) end) }, Trigger{ name="Feed", conds={holding("food")}, action=Action("Feed baby", 2, function() players.baby.props.full=min(100, players.baby.props.full+40) players.parent:drop() end) } } triggers.work = { Trigger{ name="work", conds={emptyHand}, action=Action("Work", 1, function() res.money = res.money + 30 end) } } triggers.trash = { Trigger{ name="takeTrash", conds={emptyHand}, action=Action("Take out trash", 3, function() res.trashInHand = res.trash res.trash = 0 players.parent:hold("trash") end) }, Trigger{ name="putTrashBack", conds={holding("trash")}, action=Action("Put trash back", 3, function() res.trash = res.trashInHand players.parent:drop() end) }, Trigger{ name="throw", conds={notEmptyHand, function() return not players.parent:isHolding("trash") end}, action=Action("Throw", 4, function() if res.trash >= objs.trash.maxTrash then notify("Trash is full") else players.parent:drop() res.trash = res.trash + 1 end end) } } triggers.truck = { Trigger{ name="dump", conds={holding("trash")}, action=Action("Dump trash", 3, function() players.parent:drop() res.trashInHand=0 end) } } triggers.tbl = { Trigger{ name="stash", conds={notEmptyHand, function() return objs.tbl:isEmpty() end}, action=Action("Stash item", 4, function() objs.tbl:hold(players.parent:drop()) end) }, Trigger{ name="pick", conds={emptyHand, function() return not objs.tbl:isEmpty() end}, action=Action("Pick up item", 4, function() players.parent:hold(objs.tbl:drop()) end) }, Trigger{ name="swap", conds={notEmptyHand, function() return not objs.tbl:isEmpty() end}, action=Action("Swap items",4, function() local temp = players.parent:drop() players.parent:hold(objs.tbl:drop()) objs.tbl:hold(temp) end) } } end function initConstants() t=0 colors={ label=12, meter=5, yellow=4, white=12, menuItem=10, menuItemSelected=9, menuItemText=12, menuItemProgress=6, textShadow=0, } ticsPerMin=60 ticsPerHour=ticsPerMin*60 -- starting speed, 1 tic = 1 sec costs = {diaps=30,groc=50} end function initResources() res = { money=50, groc=2, diap=2, trash=2 } end function initState() s = {} s.go = false -- game over s.goAt = 0 s.activeObj = nil s.recalcTrigs = true s.mode = "normal" end function initMenu() menu = Menu:new() end function initPlayers() players = {} players.baby = initBaby() players.parent = initParent() end function initObjs() objs = {} objs.work = Obj:new({x=100,y=15,w=4,h=4,spr=408,sc=1}) objs.dshelf = Obj:new({x=10,y=15,w=4,h=4,spr=404,sc=1}) objs.gshelf = Obj:new({x=56,y=15,w=4,h=4,spr=404,sc=1}) objs.stove = Obj:new({x=10,y=65,w=2,h=4,spr=341,sc=1}) objs.dstore = Obj:new({x=160,y=15,w=4,h=4,spr=400,sc=1}) objs.gstore = Obj:new({x=200,y=15,w=4,h=4,spr=400,sc=1}) objs.tbl = initTbl() objs.trash = initTrash() end function init() initConstants() initResources() initState() initMenu() initPlayers() initObjs() initTriggers() music(0) end init() ----------------------------------------------------------------- function animResets() -- players.parent.loc.spr=players.parent.loc.ospr end function gameOver() s.go = true s.goAt = t music() end function updateLiveliness() local babySad = players.baby:sad() if babySad and not s.go then gameOver() notify(babySad) end end function updateTimeBasedStats() players.baby:updateTimeBasedStats() end function notify(notification) s.notification = notification s.notificationAt = t end function fireEvents() players.baby:fireEvents() objs.trash:fireEvents() end function handleKeys() if s.go then if (t - s.goAt) > 120 and btn(4) then reset() end return end if s.mode == "menu" then local returnControl = menu:handleKeys() if not returnControl then return end end players.parent:handleKeys() end function calcActiveObj() local prevActive = s.activeObj s.activeObj = nil for playerName,player in pairs(players) do if playerName ~= "parent" then if isAdjacent(player:calcBloc(), players.parent:fullBloc()) then s.activeObj = playerName end end end local parentBloc = players.parent:calcBloc() for objName,obj in pairs(objs) do if isAdjacent(obj:calcBloc(), parentBloc) then s.activeObj = objName end end if s.activeObj ~= prevActive then s.recalcTrigs = true end end function calcTriggers() if not s.recalcTrigs then return end if s.activeObj == nil or triggers[s.activeObj] == nil then s.mode = "normal" else menu:empty() for tname, trigger in pairs(triggers[s.activeObj]) do if trigger:triggered() then menu:add(trigger.action) end end if #menu.actions > 0 then s.mode = "menu" else s.mode = "normal" end end s.recalcTrigs = false end function update() t=t+1 minute=(t/ticsPerHour*60) % 60 hour=(t/ticsPerHour) % 24 handleKeys() if s.go then return end animResets() updateLiveliness() updateTimeBasedStats() calcActiveObj() calcTriggers() fireEvents() end --------------------------------------------------------------- function sprint(msg,x,y,color) print(msg,x+1,y+1,colors.textShadow,true,1,true) return print(msg,x,y,color,true,1,true) end function timestamp() return string.format( "%.2d:%.2d", math.floor(hour), math.floor(minute) ) end function drawClock() spr(256,1,0,0) sprint(timestamp(),11,1,colors.label) end function drawObjs() for objName,obj in pairs(objs) do obj:draw(objName == s.activeObj) end end function drawPlayers() players.baby:draw(s.activeObj == "baby") players.parent:draw() end function drawResources() -- diapers spr(260,objs.dshelf.loc.x+1,objs.dshelf.loc.y+1,0) -- on shelf print("x"..res.diap, objs.dshelf.loc.x+11,objs.dshelf.loc.y+2, 15, false, 1, false) spr(260,objs.dstore.loc.x+20,objs.dstore.loc.y+15,0) -- on shop print("$", objs.dstore.loc.x+6,objs.dstore.loc.y+12,colors.white,false,1,false) print(costs.diaps, objs.dstore.loc.x+5,objs.dstore.loc.y+18,colors.white,true,1,true) -- grocs spr(268,objs.gshelf.loc.x+5,objs.gshelf.loc.y+1,0) -- on shelf print("x"..res.groc, objs.gshelf.loc.x+11,objs.gshelf.loc.y+2, 15, false, 1, false) spr(268,objs.gstore.loc.x+22,objs.gstore.loc.y+14,0) -- on shop print("$", objs.gstore.loc.x+6,objs.gstore.loc.y+12,colors.white,false,1,false) print(costs.groc, objs.gstore.loc.x+5,objs.gstore.loc.y+18,colors.white,true,1,true) end function drawNotifications() if s.notification and s.notificationAt and (t-s.notificationAt) < 120 then rect(0,0,240,10,0) sprint(s.notification, 120-string.len(s.notification)/2*4,2,5) end end function drawGameOver() if not s.go then return end rect(80,52,100,40,0) print("GAME OVER", 92, 64, 5*(t/10%3)) print("Score: "..s.goAt,92, 72, 5*(t/10%3)) print("Z to restart",92, 80, 5*(t/10%3)) end function drawFps() local ts = tstamp() if ts ~= pts then fps = (t - (tst or 0)) pts = ts tst = t end print(fps, 100, 0, 5) end function draw() cls() map() drawClock() drawObjs() drawResources() drawPlayers() if s.mode == "menu" then menu:draw() end drawNotifications() drawGameOver() --drawFps() end ------------------------------------------------------------------ function TIC() update() draw() end