Merge branch 'main' of https://github.com/jyelon/luprex into main
This commit is contained in:
@@ -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,41 @@ 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,... }
|
||||
-- orchard.crop='r'
|
||||
-- orchard.size=integer -- Max size it can grow to
|
||||
-- orchard.rate=integer -- How many grow per unit time()
|
||||
-- orchard.pick=integer -- time() it was last harvested
|
||||
--
|
||||
|
||||
function mapable(a)
|
||||
if isa(a,login) then return false end
|
||||
return not isa(a,player)
|
||||
end
|
||||
|
||||
function orchard:available()
|
||||
return math.min(self.size,self.rate*(time()-self.pick))
|
||||
end
|
||||
|
||||
function bound(a,b,c)
|
||||
if b<a then return b elseif b>c then return c else return b end
|
||||
end
|
||||
|
||||
function lerp(a,b,c,d,e)
|
||||
return d+(e-d)*(a-b)/(c-b)
|
||||
end
|
||||
|
||||
function orchard:harvest(n)
|
||||
local a=self:available()
|
||||
if n>=a then self.pick=time() return a end
|
||||
self.pick=lerp(n,0,a,self.pick,time())
|
||||
return n
|
||||
end
|
||||
|
||||
function player.interface(actor, place)
|
||||
gui.menu_item("cb_north" ,"Go North")
|
||||
@@ -32,9 +65,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");
|
||||
@@ -53,6 +95,7 @@ function army.interface(actor,place)
|
||||
-- Spock dismantles Scissors 2
|
||||
armytypes={'r','p','s'}
|
||||
armynames={r="Rock Golem" ,p="Paper Dragon",s="Scissor Beast",l="Fire Lizzard",v="Mr. Spock"}
|
||||
foodtypes={'r','p','s','l','v'}
|
||||
foodnames={r="Raspberry" ,p="Pomegranite" ,s="Strawberry" ,l="Lemon" ,v="Mango" }
|
||||
--advantage={ r={ r=1, p=1/2, s=3, l=2, v=1/3 },
|
||||
-- p={ r=2, p=1, s=1/2, l=1/3, v=3 },
|
||||
@@ -73,44 +116,27 @@ 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)
|
||||
end end
|
||||
-- print("Here's what was built:")
|
||||
-- pprint(nt)
|
||||
end end end
|
||||
for x=-rad,rad do for y=-rad,rad do
|
||||
itemkind=math.random(1,7)
|
||||
if itemkind==1 then
|
||||
local nt=tangible.build{class='army',x=x,y=y,z=0,plane='main',graphic='army'}
|
||||
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
|
||||
nt.stack=stack
|
||||
elseif itemkind==2 then
|
||||
local nt=tangible.build{class='orchard',x=x,y=y,z=0,plane='main',graphic='orchard'}
|
||||
nt.crop=foodtypes[math.random(1,#foodtypes)]
|
||||
nt.size=10
|
||||
nt.rate=0.1
|
||||
nt.pick=time()
|
||||
end
|
||||
end end
|
||||
end
|
||||
|
||||
|
||||
@@ -118,7 +144,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 +155,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 +263,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 +274,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 +289,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 +313,7 @@ function player:cb_east()
|
||||
end
|
||||
|
||||
function player:cb_west()
|
||||
self:walk(0,1)
|
||||
self:walk(-1,0)
|
||||
end
|
||||
|
||||
|
||||
@@ -246,38 +327,68 @@ 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 rval=""
|
||||
local prefix=""
|
||||
local suffix=""
|
||||
if isa(lis[1],player) then prefix="\27[91;7m" suffix="\27[0m" end
|
||||
if isa(lis[1],army) then
|
||||
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))
|
||||
elseif isa(lis[1],orchard) then
|
||||
rval=rval.." OO "
|
||||
end
|
||||
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' or cl=='orchard') 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 +433,7 @@ function player.cb_map(actor,place,dialog)
|
||||
-- end
|
||||
end
|
||||
|
||||
function counttoten(p1,p2,p3)
|
||||
for i=1,10 do print(i) end
|
||||
end
|
||||
|
||||
|
||||
@@ -5,12 +5,20 @@ function login.interface(actor, place)
|
||||
gui.menu_item("cb_p123", "Print 1, 2, 3")
|
||||
gui.menu_item("cb_p123_nopredict", "Print 1, 2, 3 nopredict")
|
||||
gui.menu_item("cb_uglytimedaemon","Start the Time Daemon")
|
||||
gui.menu_item("cb_seedprng","Seed the PRNG")
|
||||
end
|
||||
|
||||
function login.cb_seedprng(actor,place,dialog)
|
||||
local result=http.get{method='GET',host='www.random.org',path='/cgi-bin/randbyte',params={nbytes='32',format='f'},verifycertificate=false}
|
||||
pprint(result)
|
||||
end -- "GET /cgi-bin/randbyte?nbytes=16384&format=f HTTP/1.0\nHost: www.random.org\n\n"
|
||||
|
||||
|
||||
function login.cb_becomeplayer(actor, place, dialog)
|
||||
actor.kind='P'
|
||||
actor.Count={} setmetatable(actor.Count,NilIsZero)
|
||||
actor.Food={} setmetatable(actor.Food,NilIsZero)
|
||||
actor.stack={}
|
||||
tangible.setclass(actor, player)
|
||||
tangible.animate(actor,{action="warp",plane="main",x=0,y=0,z=0})
|
||||
end
|
||||
|
||||
@@ -27,3 +27,25 @@ 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
|
||||
|
||||
-- Example: multistart(function(t) return tangible.id(t)%3==0 end,function() print("Tangible "..tangible.id(tangible.place()).." here") end)
|
||||
function multistart(filter,closure)
|
||||
local lis=tangible.scan('nowhere',0,0,100,false)
|
||||
tabcat(lis,tangible.scan('main',0,0,100,true))
|
||||
for _,t in ipairs(lis) do if filter(t) then tangible.start(t,closure) end end
|
||||
end
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user