diff --git a/luprex/core/lua/basics.lua b/luprex/core/lua/basics.lua index c838bd52..4bcd95eb 100644 --- a/luprex/core/lua/basics.lua +++ b/luprex/core/lua/basics.lua @@ -9,3 +9,13 @@ function NilIsZero.__newindex(t,k,v) if v~=nil and v~=0 then rawset(t,k,v) end end +function seq(a,b,c) return a<=b and b<=c end + +function bound(a,b,c) + if bc then return c else return b end + end + +function lerp(a,b,c,d,e) + return d+(e-d)*(a-b)/(c-b) + end + diff --git a/luprex/core/lua/control.lst b/luprex/core/lua/control.lst index d4e9d236..66b051de 100644 --- a/luprex/core/lua/control.lst +++ b/luprex/core/lua/control.lst @@ -7,6 +7,6 @@ ut-table.lua ut-globaldb.lua ut-tablecmp.lua basics.lua +uglyglobals.lua login.lua -horps.lua - +spectra.lua diff --git a/luprex/core/lua/horps.lua b/luprex/core/lua/horps.lua index 6a0dea9c..3f5bb5a2 100644 --- a/luprex/core/lua/horps.lua +++ b/luprex/core/lua/horps.lua @@ -20,6 +20,7 @@ setmetatable(player,army) -- -- New Data Structure: -- Player.Stack={ 1=kind, 2=qty, 3=kind, 4=qty,... } +-- Player.Food[kind]=Number -- orchard.crop='r' -- orchard.size=integer -- Max size it can grow to -- orchard.rate=integer -- How many grow per unit time() @@ -70,9 +71,10 @@ 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 + for i=1,#self.stack,2 do if self.stack[i]==k then self.stack[i+1]=self.stack[i+1]+c self:cb_map() return end end self.stack[#self.stack+1]=k self.stack[#self.stack+1]=c + self:cb_map() end @@ -160,6 +162,15 @@ function fight0(ak,ac,dk,dc,tweekdefender) -- returns number of attacker casualt end +function player:near_iter(rad,kind) + local lis=tangible.near(self,rad,true,true) + local i=1 + return function() + while i<=#lis do + i=i+1 + if not kind or isa(lis[i-1],kind) then return lis[i-1] end end end + end + function stack_iter(t1) local i=0 return function() @@ -191,67 +202,23 @@ function army:counttroops() end function army:die() - print("This enemy is dying!!!") + print("You defeat the enemy!") 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 + if enemy:counttroops()==0 then enemy:die() return false + else return true end 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 - local useloss0 - local useloss1=-1 - local loss0,loss1 - local whichdk, whichdc - for dk,dc in pairs(enemy.Count) do - loss0,loss1=army.fight0(ak,ac,dk,dc) - print("When "..ac.." "..ak.." fight "..dc.." "..dk.." they kill "..loss1.." and suffer "..loss0) - if loss1>useloss1 then - enemyk=dk - enemyc=dc - useloss1=loss1 - useloss0=loss0 - end end - if enemyk then - print("Army of "..ac.." "..ak.." fights "..enemyc.." "..enemyk..", killing "..useloss1.." and suffering "..useloss0) - rval[1+#rval]={'fight',ak,ac,useloss0,enemyk,enemyc,useloss1} - enemy.Count[enemyk]=enemy.Count[enemyk]-useloss1 - self.Count[ak]=self.Count[ak]-useloss0 - end - end - local enemyleft=0 - local playerleft=0 - for dk,dc in pairs(enemy.Count) do enemyleft=enemyleft+dc end - for ak,ac in pairs(self.Count) do playerleft=playerleft+ac end - rval.enemyleft=enemyleft - return rval - end - - - function player:cb_droprock(actor) player:droparmy(actor,'r') end function player:cb_droppaper(actor) player:droparmy(actor,'p') end function player:cb_dropscissor(actor) player:droparmy(actor,'s') end @@ -265,20 +232,23 @@ function player:droparmy(actor,kind) t.Count[kind]=t.Count[kind]+1 end -function orchard:gather(actor) - actor.food[self.kind]=actor.inventory[self.kind]+self.count +function player:pickfruit(ft) + local kind=ft.crop + local qty=ft:harvest(ft:available()) + self.food[kind]=self.food[kind]+qty + print("You harvest "..qty.." "..foodnames[kind]) end -function player:newlocation() +function player:newlocation() -- return false if the player should bounce back, else return true local lis=tangible.near(self,0,true,true) local count={} setmetatable(count,NilIsZero) local count0=0 - local result={} - for _,t in ipairs(lis) do if isa(t,army) then - result[1+#result]=self:fight(t) - end end - pprint(result) - return result + local bounce=false + for _,t in ipairs(lis) do + if isa(t,army) then bounce=bounce or self:fight(t) + elseif isa(t,orchard) then self:pickfruit(t) end + end + return bounce end function player:printanimstate() @@ -288,16 +258,8 @@ function player:printanimstate() function player:walk(dx,dy) tangible.animate(self,{action='walk',dx=dx,dy=dy}) - local result=self:newlocation() - if #result>1 then print("Error: multiple armies at one location") - elseif #result==1 then - tangible.animate(self,{action='walk',dx=-dx,dy=-dy}) end + if self:newlocation() then 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 - end - end end function player:cb_north() @@ -337,6 +299,7 @@ function where() print("You are at "..x.." "..y) end + function mapcelltext(lis) if lis==nil then return ' ' end if #lis>1 then return '++++++' end @@ -348,14 +311,15 @@ function mapcelltext(lis) 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 " + prefix="\27[32;1m" suffix="\27[0m" + rval=rval..lis[1].crop..string.format("%-5d",lis[1]:available()) end return prefix..rval..suffix end function player.cb_map(actor,place,dialog) - print("\27c\27[38;5;9mMap:\27[0m") + print("\27[s\27[0;0f") local rad=4 local ax,ay=tangible.xyz(actor) scratch={} @@ -378,62 +342,8 @@ function player.cb_map(actor,place,dialog) lbuf=lbuf..'|' print(lbuf) end + print("\27[u") 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 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]={} scratch[offset].Count={} setmetatable(scratch[offset].Count,NilIsZero) end - if t.Count then - for i,k in ipairs(armytypes) do - local a0=scratch[offset] - local a1=a0.Count - local a2=a1[i] - local a3=t.Count - local a4=a3[k] - if not a4 then print("a4 is nil") pprint(t) end - scratch[offset].Count[i]=a2+a4 - end end - end - end --- pprint(scratch) - for dy=-rad,rad do for line=0,1 do - local lbuf="|" - for dx=-rad,rad do - local offset=(dy+rad)*(rad*2+1)+dx+rad - if line==0 then lbuf=lbuf.."----" - elseif line==1 then - if scratch[offset] then for i,k in ipairs(armytypes) do lbuf=lbuf..scratch[offset].Count[i] end - else for i=1,#armytypes do lbuf=lbuf..' ' end end - lbuf=lbuf.."-" - end end - print(lbuf) - end end - lbuf="" - for dx=-rad,rad do lbuf=lbuf.."----" end - lbuf=lbuf.."-" - print(lbuf) --- print("In Player "..tangible.id(actor)..":") --- for k,v in pairs(actor.Count) do print(" "..k.." "..v) end --- local lis=tangible.near(actor,0,true,true) --- for k,v in pairs(lis) do --- print("In Army "..tangible.id(v)..":") --- for k2,v2 in pairs(v.Count) do print(" "..k2.." "..v2) end --- end - end - -function counttoten(p1,p2,p3) - for i=1,10 do print(i) end - end - diff --git a/luprex/core/lua/login.lua b/luprex/core/lua/login.lua index 888ef352..2eabdde1 100644 --- a/luprex/core/lua/login.lua +++ b/luprex/core/lua/login.lua @@ -17,8 +17,10 @@ function login.cb_seedprng(actor,place,dialog) function login.cb_becomeplayer(actor, place, dialog) actor.kind='P' actor.Count={} setmetatable(actor.Count,NilIsZero) - actor.Food={} setmetatable(actor.Food,NilIsZero) + actor.food={} setmetatable(actor.food,NilIsZero) + actor.spectra={} setmetatable(actor.spectra,NilIsZero) actor.stack={} + actor.team='red' tangible.setclass(actor, player) tangible.animate(actor,{action="warp",plane="main",x=0,y=0,z=0}) end diff --git a/luprex/core/lua/spectra.lua b/luprex/core/lua/spectra.lua new file mode 100644 index 00000000..668ddc84 --- /dev/null +++ b/luprex/core/lua/spectra.lua @@ -0,0 +1,162 @@ +makeclass('player') +makeclass('light') + +freqcolor={ azure=152, black=35200, blue=59300, brown=20000, chocolate=1840, cream=8610, + crimson=575, fawn=272, gold=17300, green=34200, grey=17300, lemon=445, + lilac=1020, mauve=719, ochre=132, olive=1910, orange=22500, peach=3860, + pink=27200, purple=13700, red=52200, rose=4310, ruby=994, russet=68, + scarlet=315, silver=13200, violet=3590, white=45100, yellow=24400 } + +function player:near_iter(rad,kind1,kind2,kind3) + local lis=tangible.near(self,rad,true,true) + local i=1 + return function() + while i<=#lis do + i=i+1 + if not kind1 or isa(lis[i-1],kind1,kind2,kind3) then return lis[i-1] end end end + end + +function tandist(t1,t2) + local _,t1p,t1x,t1y=tangible.animstate(t1) + local _,t2p,t2x,t2y=tangible.animstate(t2) + return math.sqrt((t1x-t2x)*(t1x-t2x)+(t1y-t2y)*(t1y-t2y)) + end + +function player:radius_iter(rad,kind) + local lis=tangible.near(self,rad,true,true) + local i=1 + return function() + while i<=#lis do + i=i+1 + if (not kind or isa(lis[i-1],kind)) and tandist(self,lis[i-1])<=rad then return lis[i-1] end end end + end + +function player:interface(place) + gui.menu_item("cb_dir0" ,"Go North") + gui.menu_item("cb_dir180" ,"Go South") + gui.menu_item("cb_dir270" ,"Go West") + gui.menu_item("cb_dir90" ,"Go East") + gui.menu_item("cb_map" ,"Map") + gui.menu_item("cb_spectra" ,"Show Spectra") + end + +function player:cb_spectra() + for k,v in pairs(self.spectra) do print(string.format("%-6.6s:%s",k,string.sub('+++++++++++++++++++++++++',1,v))) end + end + +function player:cb_dir0() self:move(0) end +function player:cb_dir45() self:move(45) end +function player:cb_dir90() self:move(90) end +function player:cb_dir135() self:move(135) end +function player:cb_dir180() self:move(180) end +function player:cb_dir215() self:move(215) end +function player:cb_dir270() self:move(270) end +function player:cb_dir315() self:move(315) end + +function player:power() + local rval=0 + for k,v in pairs(self.spectra) do if v>0 then rval=rval+1 end end + return rval + end + +function player:respawn() + tangible.animate(self,{action='warp',plane='main',x=math.random(-40,40),y=math.random(-40,40),z=0}) + self:cb_map() + print("You just died!") -- + end + +function player:fight(enemy) + local common={} + for k,v in pairs(self.spectra) do if enemy.spectra[k]>0 then common[k]=1 end end + local p0=self:power() + local p1=enemy:power() + local winner + if p0==p1 then + for k,v in pairs(common) self.spectra[k]=nil enemy.spectra[k]=nil end + else if p0>p1 then + for k,v in pairs(common) enemy.spectra[k]=nil end + else + for k,v in pairs(common) self.spectra[k]=nil end + end + p0=self:power() + p1=enemy:power() + if p1==0 then self.kills =self.kills+1 enemy.deaths=enemy.deaths+1 enemy:respawn() end + if p0==0 then self.deaths=self.deaths+1 enemy.kills =enemy.kills+1 self:respawn() end + end + + +function player:newlocation() + for lt in self:radius_iter(3.1,light) do self.spectra[lt.color]=25 end + for lt in self:radius_iter(3.1,player) do if self.team==lt.team then + local nspec={} setmetatable(nspec,NilIsZero) + for k,v in pairs(self.spectra) do nspec[k]=v end + for k,v in pairs(lt.spectra) do nspec[k]=math.max(v,nspec[k]) end + for k,v in pairs(nspec) do self.spectra[k]=v lt.spectra[k]=v end + end end + for lt in self:radius_iter(3.1,player) do if self.team~=lt.team then p1:fight(p2) end end + for k,v in pairs(self.spectra) do self.spectra[k]=self.spectra[k]-1 if self.spectra[k]<=0 then self.spectra[k]=nil end end + end + + +function player:move(degrees) + dx= math.cos((90-degrees)*math.pi/180) + dy=-math.sin((90-degrees)*math.pi/180) + tangible.animate(self,{action='walk',dx=dx,dy=dy}) + self:newlocation() + self:map(12) + end + +function wrcolor() + local acc=0 + local rval + for k,v in pairs(freqcolor) do acc=acc+v if math.random(1,acc)<=v then rval=k end end + return rval + end + +function makemap() + for i=1,100 do + local x=math.random(-50,50) + local y=math.random(-50,50) + local nt=tangible.build{class='light',x=x,y=y,z=0,plane='main',graphic='light'} + nt.color=wrcolor() + end + end + +function setcell(array,x,y,val) + if not array[y] then array[y]={} end + array[y][x]=val + return array + end + +function player:cb_map(place,dialog) + self:map(10) + end + +teamcolor={ red='\27[91m', green='\27[92m', yellow='\27[93m', blue='\27[94m', magenta='\27[95m', cyan='\27[96m' } + +function player:map(radius) + local radius=10 + radius=radius or 10 + local cells={} + local px,py=tangible.xyz(tangible.actor()) + for lt in self:near_iter(1.5*radius,light,player) do + local lx,ly=tangible.xyz(lt) + lx=lx-px+radius + ly=ly-py+radius + if seq(0,ly,1+2*radius) and seq(0,lx,1+2*radius) then + local celltext + if isa(lt,light) then celltext=string.format("%-6.6s",lt.color) + elseif isa(lt,player) then celltext=teamcolor[lt.team].."Pl:"..string.format("%-3.0f",lt:power()).."\27[0m" + end + setcell(cells,math.floor(0.5+lx),math.floor(0.5+ly),celltext) end + end + setcell(cells,radius,radius,teamcolor[self.team]..string.format("Me:%-3.0f",self:power()).."\27[0m") + for ly=0,1+2*radius do + local line='|' + for lx=0,1+2*radius do + if cells[ly] and cells[ly][lx] then line=line..cells[ly][lx]..'|' else line=line..' |' end + end + print(line) + end + end + diff --git a/luprex/core/lua/uglyglobals.lua b/luprex/core/lua/uglyglobals.lua index f7f0299a..6b299929 100644 --- a/luprex/core/lua/uglyglobals.lua +++ b/luprex/core/lua/uglyglobals.lua @@ -28,12 +28,12 @@ function login.cb_uglytimedaemon() function time() return ug.get('time') end -function isa(k1,k2) - if k1==k2 then return true end +function isa(k1,k2,k3,k4) + if k1==k2 or k1==k3 or k1==k4 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) + return isa(mt.__index,k2,k3,k4) end function tabcat(t1,t2) @@ -41,9 +41,10 @@ function tabcat(t1,t2) 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) +function multistart(fil,closure) local lis=tangible.scan('nowhere',0,0,100,false) tabcat(lis,tangible.scan('main',0,0,100,true)) + local filter=type(fil)=='function' and fil or function(t) return isa(t,fil) end for _,t in ipairs(lis) do if filter(t) then tangible.start(t,closure) end end end diff --git a/luprex/core/lua/util.lua b/luprex/core/lua/util.lua new file mode 100644 index 00000000..e69de29b