diff --git a/luprex/core/lua/horps.lua b/luprex/core/lua/horps.lua index 0b567126..900e838e 100644 --- a/luprex/core/lua/horps.lua +++ b/luprex/core/lua/horps.lua @@ -2,6 +2,8 @@ makeclass('player') makeclass('army') makeclass('orchard') +setmetatable(player,army) + -- -- HORPS game: Walk around the board collecting armies and buffs -- Captured armies eat each turn @@ -12,10 +14,13 @@ makeclass('orchard') -- -- --- Data Structure +-- Old Data Structure -- Army.Count[kind]=number Where kind is r,p,s -- Player.Count[kind]=number Where kind is r,p,s -- +-- New Data Structure: +-- Player.Stack={ 1=kind, 2=qty, 3=kind, 4=qty,... } +-- function player.interface(actor, place) gui.menu_item("cb_north" ,"Go North") @@ -32,9 +37,18 @@ function player.interface(actor, place) end -function player:cb_conjurerock() self.Count['r']=self.Count['r']+1 end -function player:cb_conjurepaper() self.Count['p']=self.Count['p']+1 end -function player:cb_conjurescissor() self.Count['s']=self.Count['s']+1 end +function player:cb_conjurerock() self:conjure('r',1) end +function player:cb_conjurepaper() self:conjure('p',1) end +function player:cb_conjurescissor() self:conjure('s',1) end + +function player:conjure(k,c) + for i=1,#self.stack,2 do if self.stack[i]==k then self.stack[i+1]=self.stack[i+1]+c return end end + self.stack[#self.stack+1]=k + self.stack[#self.stack+1]=c + end + + + function army.interface(actor,place) if place.owner==actor then gui_menu_item("cb_recruit","Recruit"); @@ -73,43 +87,18 @@ function shuffle(t) return s end -function qbuildarmy(x,y) - t={class='army',x=x,y=y,z=0,plane='main',graphic='army'} - local nt=tangible.build(t) - nt.Count={} - setmetatable(nt.Count,NilIsZero) - nt.Count['r']=1 - return nt - end - -function MakeMap2() - for i=-2,2 do - qbuildarmy( i, 3) - qbuildarmy( i,-3) - qbuildarmy(-3, i) - qbuildarmy( 3, i) - end - qbuildarmy(-3, 3) - qbuildarmy( 3,-3) - qbuildarmy(-3,-3) - qbuildarmy( 3, 3) - end - function MakeMap() local rad=6 for x=-rad,rad do for y=-rad,rad do if math.random(1,5)==1 then t={class='army',x=x,y=y,z=0,plane='main',graphic='army'} --- print("Building an army:") --- pprint(t) local nt=tangible.build(t) - nt.Count={} - setmetatable(nt.Count,NilIsZero) - for i=1,#armytypes do if math.random(1,2)==1 then - local type=armytypes[math.random(1,#armytypes)] - nt.Count[type]=nt.Count[type]+math.random(1,3) + local stack={} + local shuf=shuffle(armytypes) + for i=1,#shuf do if math.random(1,2)==1 then + stack[1+#stack]=shuf[i] + stack[1+#stack]=math.random(1,3) end end --- print("Here's what was built:") --- pprint(nt) + nt.stack=stack end end end end @@ -118,7 +107,7 @@ function MakeMap() -- -- For each creature type, select the optimal target. Select randomly among identical targets. -- -function army.fight0(ak,ac,dk,dc,tweekdefender) -- returns number of attacker casualties, defender casualties +function fight0(ak,ac,dk,dc,tweekdefender) -- returns number of attacker casualties, defender casualties local adv0=advantage[ak][dk] local adv1=advantage[dk][ak] if not tweekdefender then tweekdefender=function(adv) return adv end end @@ -129,12 +118,70 @@ function army.fight0(ak,ac,dk,dc,tweekdefender) -- returns number of attacker ca local powertotal=power0+power1 local loss0=math.min(ac,math.floor(losstotal*power1/powertotal)) local loss1=math.min(dc,math.floor(losstotal*power0/powertotal)) + if loss0+loss1==0 then loss0=loss0+1 end return loss0,loss1 end +function stack_iter(t1) + local i=0 + return function() + if i+2>#t1 then return end + i=i+2 + return t1[i-1],t1[i] + end end -function player:fight(enemy) +function fight_iter(t1,t2) -- Returns quads: AttackerKind,AttackerCount,DefenderKind,DefenderCount + local i=0 + return function() + if i+2>#t1 or i+2>#t2 then return end + i=i+2 + return t1[i-1],t1[i],t2[i-1],t2[i] + end end + +function compactstack(s) + local index=1 + while index<=#s do + if s[index+1]==0 then table.remove(s,index) table.remove(s,index) + else index=index+2 end + end + end + +function army:counttroops() + local rval=0 + for k,c in stack_iter(self.stack) do rval=rval+c end + return rval + end + +function army:die() + print("This enemy is dying!!!") + tangible.delete(self) + print("And now it is dead, so sad") + end + +function army:fight(enemy) + print("Fight!!!") + local rval={} + for i=1,math.min(#self.stack,#enemy.stack),2 do + loss1,loss2=fight0(self.stack[i],self.stack[i+1],enemy.stack[i],enemy.stack[i+1]) + print("When "..self.stack[i+1].." "..self.stack[i].." fight "..enemy.stack[i+1].." "..enemy.stack[i].." they kill "..loss2.." and suffer "..loss1) + rval[1+#rval]={'fight',self.stack[i],self.stack[i+1],loss1,enemy.stack[i],enemy.stack[i+1],loss2} + self.stack[i+1]=self.stack[i+1]-loss1 + enemy.stack[i+1]=enemy.stack[i+1]-loss2 + end + compactstack(self.stack) + compactstack(enemy.stack) + if enemy:counttroops()==0 then enemy:die() end + return rval + end + +-- for ak,ac,dk,dc in fight_iter(self.stack,enemy.stack) do +-- loss1,loss2=fight0(ak,ac,dk,dc) +-- print("When "..ac.." "..ak.." fight "..dc.." "..dk.." they kill "..loss2.." and suffer "..loss1) +-- rval[1+#rval]={'fight',ak,ac,loss1,dk,dc,loss2} +-- end + +function player:xfight(enemy) local rval={} for ak,ac in pairs(self.Count) do -- Should randomize the order local enemyk, enemyc @@ -179,7 +226,6 @@ function player:droparmy(actor,kind) local t=lis[1] if t==nil then t=player:buildarmy(actor) end t.Count[kind]=t.Count[kind]+1 - pprint(t) end function orchard:gather(actor) @@ -191,10 +237,10 @@ function player:newlocation() local count={} setmetatable(count,NilIsZero) local count0=0 local result={} - for _,t in ipairs(lis) do if tangible.getclass(t)=='army' then result[1+#result]=self:fight(t) end end - if #result==1 and result[1].enemyleft>0 then - for _,t in ipairs(lis) do if tangible.getclass(t)=='orchard' then t:gather(self) end end - end + for _,t in ipairs(lis) do if isa(t,army) then + result[1+#result]=self:fight(t) + end end + pprint(result) return result end @@ -206,12 +252,10 @@ function player:printanimstate() function player:walk(dx,dy) tangible.animate(self,{action='walk',dx=dx,dy=dy}) local result=self:newlocation() - pprint(result) if #result>1 then print("Error: multiple armies at one location") elseif #result==1 then - if result[1].enemyleft>0 then tangible.animate(self,{action='walk',dx=-dx,dy=-dy}) end - end --- self:cb_map() + tangible.animate(self,{action='walk',dx=-dx,dy=-dy}) end + self:cb_map() if #result==1 then for i,v in ipairs(result[1]) do if v[1]=='fight' then print(v[3]..v[2].." attacks "..v[6]..v[5]..", killing "..v[7].." while losing "..v[4]) end @@ -232,7 +276,7 @@ function player:cb_east() end function player:cb_west() - self:walk(0,1) + self:walk(-1,0) end @@ -246,38 +290,65 @@ function player:buildarmy(actor) end -function player.cb_emit_army(actor,place,dialog) - local _,pl,ax,ay=tangible.animstate(actor) - t={class='army',x=ax,y=ay,z=0,plane=pl,graphic='army'} - pprint("building ",t) - local nt=tangible.build(t) - setmetatable(nt,{r=0,p=0,s=0}) - nt.kind='r' - nt.Count=1 - end - -function player.cb_emit_buff(actor,place,dialog) - local _,pl,ax,ay=tangible.animstate(actor) - t={class='army',x=ax,y=ay,z=0,plane=pl,graphic='buff'} - pprint("building ",t) - tangible.build(t) - end - makeclass('army') -makeclass('buff') - function seq(a,b,c) return a<=b and b<=c or false end function num2(a) if a<=9 then return " "..a else return a end end +function where() + local x,y,z=tangible.xyz(tangible.actor()) + print("You are at "..x.." "..y) + end + +function mapcelltext(lis) + if lis==nil then return ' ' end + if #lis>1 then return '++++++' end + local acc={} setmetatable(acc,NilIsZero) + local rval="" + local prefix="" + local suffix="" + if isa(lis[1],player) then prefix="\27[91;7m" suffix="\27[0m" end + for k,c in stack_iter(lis[1].stack) do rval=rval..k..(c>9 and '+' or tostring(c)) end + rval=rval..string.sub(' ',1,6-string.len(rval)) + return prefix..rval..suffix + end + + function player.cb_map(actor,place,dialog) + print("\27c\27[38;5;9mMap:\27[0m") + local rad=4 + local ax,ay=tangible.xyz(actor) + scratch={} + local lis=tangible.near(actor,1.5*rad,true,false) + for _,t in pairs(lis) do + local c=tangible.getclass(t) + local dx,dy=tangible.xyz(t) + local offset=(-dy+ay+rad)*(rad*2+1)+dx-ax+rad + local cl=tangible.getclass(t) + if seq(ax-rad,dx,ax+rad) and seq(ay-rad,dy,ay+rad) and (cl=='player' or cl=='army') then + if not scratch[offset] then scratch[offset]={} end + scratch[offset][1+#scratch[offset]]=t + end end + for dy=-rad,rad do + local lbuf="" + for dx=-rad,rad do + local offset=(dy+rad)*(rad*2+1)+dx+rad + lbuf=lbuf..'|'..mapcelltext(scratch[offset]) + end + lbuf=lbuf..'|' + print(lbuf) + end + end + + + +function player.xcb_map(actor,place,dialog) local rad=4 local ax,ay=tangible.xyz(actor) local scratch={} local lis=tangible.near(actor,1.5*rad,true,false) print("\27c\27[38;5;9mMap:\27[0m") for _,t in pairs(lis) do --- local graphic,plane,x,y,z,facing = tangible.animstate(t) local c=tangible.getclass(t) local dx,dy=tangible.xyz(t) local offset=(-dy+ay+rad)*(rad*2+1)+dx-ax+rad @@ -322,3 +393,7 @@ function player.cb_map(actor,place,dialog) -- end end +function counttoten(p1,p2,p3) + for i=1,10 do print(i) end + end + diff --git a/luprex/core/lua/uglyglobals.lua b/luprex/core/lua/uglyglobals.lua index 63bfe737..4973692c 100644 --- a/luprex/core/lua/uglyglobals.lua +++ b/luprex/core/lua/uglyglobals.lua @@ -27,3 +27,24 @@ function login.cb_uglytimedaemon() end function time() return ug.get('time') end + +function isa(k1,k2) + if k1==k2 then return true end + if k1==nil then return false end + local mt=getmetatable(k1) + if not mt then return false end + return isa(mt.__index,k2) + end + +function tabcat(t1,t2) + for i=1,#t2 do t1[#t1+1]=t2[i] end + end + +function multistart(filter,closure) + local lis=tangible.scan('nowhere',0,0,1000000000,false) + lis=tabcat(lis,tangible.scan('main',0,0,1000000000,true) + for _,t in iparis(lis) do if filter(t) then closure(t) end end + end + + + \ No newline at end of file