WIP robot creation in board editor!
- refactor client - now has a _stack_ of current Games, the top of which is active - prevents shutdown of whiteboard when "leaving" to edit source code - add tpers.StaticIndex / inspector.py for interactively querying object graphs
This commit is contained in:
parent
f7c33a23a6
commit
10edbacf86
31
basetoken.py
31
basetoken.py
|
@ -73,7 +73,7 @@ class Terminal(Token):
|
|||
self.fBlink = fBlink
|
||||
|
||||
def getKey(self):
|
||||
return self.client.evKey.receive(self)
|
||||
return self.client.EvKey(self.game).receive(self)
|
||||
|
||||
def getPrintableKey(self):
|
||||
while True:
|
||||
|
@ -199,8 +199,13 @@ class Terminal(Token):
|
|||
|
||||
class LeaveJoinToken(Token):
|
||||
def run(self):
|
||||
evLeave = self.game.evSuspend if self.FOnActivate() else self.game.evLeave
|
||||
evJoin = self.game.evActivate if self.FOnActivate() else self.game.evJoin
|
||||
while True:
|
||||
Event.selectDg(self, (self.game.evLeave, self.OnLeave), (self.game.evJoin, self.OnJoin))
|
||||
Event.selectDg(self, (evLeave, self.OnLeave), (evJoin, self.OnJoin))
|
||||
|
||||
def FOnActivate(self):
|
||||
return False
|
||||
|
||||
class AutoJoiner(LeaveJoinToken):
|
||||
def InitPersistent(self, owner, *rgclsTok):
|
||||
|
@ -234,6 +239,9 @@ class AliveWithPlayers(LeaveJoinToken):
|
|||
Token.InitTransient(self)
|
||||
self.rgclient = []
|
||||
|
||||
def FOnActivate(self):
|
||||
return True
|
||||
|
||||
def OnLeave(self, client):
|
||||
self.rgclient.remove(client)
|
||||
if len(self.rgclient) == 0:
|
||||
|
@ -705,9 +713,18 @@ class MiMenuHoriz(MiMenuI):
|
|||
mi.DrawWithParent(selor, ascr, x, y, wT, miSelected == mi)
|
||||
x = x + wT
|
||||
|
||||
def DgProjectMiButton(dgExec):
|
||||
class ProjectedValue(TPrs):
|
||||
def InitPersistent(self, value, dgStName):
|
||||
self.value = value
|
||||
self.dgStName = dgStName
|
||||
def StName(self):
|
||||
return self.dgStName(self.value)
|
||||
def Value(self):
|
||||
return self.value
|
||||
|
||||
def DgProjectMiButton(dgExec, dgStName = None):
|
||||
def DgProject(value):
|
||||
return MiButton(None, lambda: dgExec(value), value)
|
||||
return MiButton(None, lambda: dgExec(value), ProjectedValue(value, dgStName) if dgStName else value)
|
||||
return DgProject
|
||||
|
||||
class RgmiProjected(TPrs):
|
||||
|
@ -781,13 +798,15 @@ class OvStatic(TokenClient):
|
|||
|
||||
def Value(self, stName = None):
|
||||
return self.miMenu.Value(stName)
|
||||
|
||||
class OvMenu(OvStatic):
|
||||
def run(self):
|
||||
while True:
|
||||
self.miMenu.HandleKey(self.client.evKey.receive(self))
|
||||
self.miMenu.HandleKey(self.client.EvKey(self.game).receive(self))
|
||||
|
||||
def draw(self, ascr, client):
|
||||
self.drawI(ascr, client, True)
|
||||
|
||||
class OvPopup(OvStatic):
|
||||
def InitPersistent(self, owner, client, miMenu):
|
||||
OvStatic.InitPersistent(self, owner, client, miMenu, self.MIDDLE, "drawable", "menu")
|
||||
|
@ -800,7 +819,7 @@ class OvPopup(OvStatic):
|
|||
self.evShow.receive(self)
|
||||
self.fAwake = True
|
||||
while self.fAwake:
|
||||
key = self.client.evKey.receive(self)
|
||||
key = self.client.EvKey(self.game).receive(self)
|
||||
if not self.miMenu.HandleKey(key):
|
||||
if key == ansi.K_TAB or key == ansi.K_DEL or key == ' ' or ansi.FEnter(key):
|
||||
self.fAwake = False
|
||||
|
|
98
engine.py
98
engine.py
|
@ -184,7 +184,7 @@ class Ownable(TPrs):
|
|||
tok.die()
|
||||
self.DontPersist()
|
||||
|
||||
@Version(2)
|
||||
@Version(3)
|
||||
class Game(Ownable):
|
||||
def InitPersistent(self):
|
||||
Ownable.InitPersistent(self)
|
||||
|
@ -194,12 +194,16 @@ class Game(Ownable):
|
|||
self.rgdgdie = []
|
||||
self.evJoin = Event(self)
|
||||
self.evLeave = Event(self)
|
||||
self.evActivate = Event(self)
|
||||
self.evSuspend = Event(self)
|
||||
self.mpuser_cldg = {}
|
||||
self.CreateRgtok(self.GetRgclsTokPers(), True)
|
||||
|
||||
def InitTransient(self):
|
||||
self.MakeTransient("fScheduled", False)
|
||||
self.rgclient = []
|
||||
self.rgclientActive = []
|
||||
self.rgclientSuspended = []
|
||||
self.rgclientLeaving = []
|
||||
self.rgproc = [PTimer(), PEvent(), PDraw(*self.GetRgtagDraw())]
|
||||
for proc in self.rgproc:
|
||||
proc.setGame(self)
|
||||
|
@ -240,6 +244,9 @@ class Game(Ownable):
|
|||
if not fPersist:
|
||||
tok.DontPersist()
|
||||
|
||||
def RgclientConnected(self):
|
||||
return self.rgclientActive + self.rgclientSuspended
|
||||
|
||||
def tagToken(self, token, tag):
|
||||
if not (tag in self.mptagTokenset):
|
||||
self.mptagTokenset[tag] = set([token])
|
||||
|
@ -268,10 +275,12 @@ class Game(Ownable):
|
|||
return rgtoken
|
||||
|
||||
def quit(self):
|
||||
assert len(self.rgclientSuspended) == 0
|
||||
self.running = False
|
||||
self.fQuit = True
|
||||
|
||||
def finish(self, rc = None):
|
||||
assert len(self.rgclientSuspended) == 0
|
||||
self.running = False
|
||||
self.rc = rc
|
||||
class QuitException(Exception):
|
||||
|
@ -291,22 +300,44 @@ class Game(Ownable):
|
|||
proc.process()
|
||||
if not self.running:
|
||||
self.die()
|
||||
for client in self.rgclient:
|
||||
for client in self.rgclientActive:
|
||||
if client not in self.rgclientLeaving:
|
||||
client.leaveGame(self.rc)
|
||||
for client in self.rgclient:
|
||||
deadClients = list(self.rgclientLeaving)
|
||||
del self.rgclientLeaving[:]
|
||||
for client in deadClients:
|
||||
if client in self.rgclientActive:
|
||||
self.rgclientActive.remove(client)
|
||||
if client in self.rgclientSuspended:
|
||||
self.rgclientSuspended.remove(client)
|
||||
client.postRunStep()
|
||||
finally:
|
||||
self.fScheduled = False
|
||||
return self.running
|
||||
def joinGame(self,client):
|
||||
self.rgclient.append(client)
|
||||
self.rgclientActive.append(client)
|
||||
self.evJoin.fire(client)
|
||||
self.evActivate.fire(client)
|
||||
|
||||
def leaveGame(self, client):
|
||||
if self.running:
|
||||
if client in self.rgclientActive:
|
||||
self.evSuspend.fire(client)
|
||||
self.evLeave.fire(client)
|
||||
self.rgclientLeaving.append(client)
|
||||
|
||||
def reactivateClient(self, client):
|
||||
assert client in self.rgclientSuspended
|
||||
self.rgclientSuspended.remove(client)
|
||||
self.rgclientActive.append(client)
|
||||
self.evActivate.fire(client)
|
||||
|
||||
def suspendClient(self, client):
|
||||
assert client in self.rgclientActive
|
||||
self.rgclientActive.remove(client)
|
||||
self.rgclientSuspended.append(client)
|
||||
self.evSuspend.fire(client)
|
||||
|
||||
def leaveGameI(self, client):
|
||||
self.rgclient.remove(client)
|
||||
def ensureRun(self):
|
||||
self.running = True
|
||||
if not self.fScheduled:
|
||||
|
@ -315,6 +346,9 @@ class Game(Ownable):
|
|||
def UpgradeFrom(self, versionOld):
|
||||
if versionOld < 2:
|
||||
self.mpuser_cldg = {}
|
||||
if versionOld < 3:
|
||||
self.evActivate = Event(self)
|
||||
self.evSuspend = Event(self)
|
||||
|
||||
# Client data
|
||||
@Version(2)
|
||||
|
@ -336,9 +370,9 @@ class Client(TPrs):
|
|||
def InitTransient(self):
|
||||
self.chRun = stackless.channel()
|
||||
self.gameCurr = None
|
||||
self.mpgame_evKey = {}
|
||||
self.rggameSuspended = []
|
||||
self.chCont = None
|
||||
self.fRunning = False
|
||||
self.dgJoinGame = None
|
||||
self.rgdgQuit = []
|
||||
self.fQuit = False
|
||||
self.cld = None
|
||||
|
@ -353,19 +387,33 @@ class Client(TPrs):
|
|||
if self._runTskRun():
|
||||
self.gameCurr.ensureRun()
|
||||
def joinGame(self, game):
|
||||
assert not self.fRunning, "already running"
|
||||
if not self.gameCurr:
|
||||
chCont = stackless.channel()
|
||||
self.chRun.send((game, chCont))
|
||||
return chCont.receive()
|
||||
else:
|
||||
self.gameCurr.suspendClient(self)
|
||||
self.rggameSuspended.append(self.gameCurr)
|
||||
self.gameCurr = game
|
||||
self.gameCurr.joinGame(self)
|
||||
|
||||
def leaveGame(self, rc = None):
|
||||
self.fRunning = False
|
||||
self.gameCurr.leaveGame(self)
|
||||
if self.gameCurr in self.mpgame_evKey:
|
||||
del self.mpgame_evKey[self.gameCurr]
|
||||
|
||||
if len(self.rggameSuspended) == 0:
|
||||
self.gameCurr = None
|
||||
self.rc = rc
|
||||
else:
|
||||
self.gameCurr = self.rggameSuspended.pop()
|
||||
self.gameCurr.reactivateClient(self)
|
||||
|
||||
def quit(self):
|
||||
while self.gameCurr:
|
||||
self.leaveGame(None)
|
||||
self.fQuit = True
|
||||
|
||||
def _runTskRun(self):
|
||||
"run self.tskRun after it has been scheduled, and await results"
|
||||
stackless.run()
|
||||
|
@ -373,20 +421,17 @@ class Client(TPrs):
|
|||
return False
|
||||
self.gameCurr, self.chCont = self.chRun.receive()
|
||||
self.gameCurr.joinGame(self)
|
||||
self.fRunning = True
|
||||
if self.dgJoinGame:
|
||||
self.dgJoinGame(self, self.gameCurr)
|
||||
return True
|
||||
|
||||
def postRunStep(self):
|
||||
if not self.fRunning:
|
||||
self.gameCurr.leaveGameI(self)
|
||||
if not self.gameCurr:
|
||||
if not self.fQuit:
|
||||
self.chCont.send(self.rc)
|
||||
self.fQuit = not self._runTskRun()
|
||||
if self.fQuit:
|
||||
for dgQuit in self.rgdgQuit:
|
||||
dgQuit()
|
||||
del self.rgdgQuit[:]
|
||||
return self.fQuit
|
||||
def beep(self):
|
||||
pass
|
||||
|
@ -401,9 +446,18 @@ class Client(TPrs):
|
|||
|
||||
def removeDgQuit(self, dgquit):
|
||||
self.rgdgQuit.remove(dgquit)
|
||||
def Cldg(self, game = None):
|
||||
if game == None:
|
||||
game = self.gameCurr
|
||||
|
||||
def EvKey(self, game):
|
||||
if game:
|
||||
if game not in self.mpgame_evKey:
|
||||
self.mpgame_evKey[game] = Event(game)
|
||||
return self.mpgame_evKey[game]
|
||||
|
||||
def KeyPressed(self, ch):
|
||||
if self.gameCurr:
|
||||
self.EvKey(self.gameCurr).fire(ch)
|
||||
|
||||
def Cldg(self, game):
|
||||
return game.GetCldg(self.cld.user)
|
||||
|
||||
class Processor(TPrs):
|
||||
|
@ -463,7 +517,7 @@ class PDraw(Processor):
|
|||
|
||||
def process(self):
|
||||
if self.game.ms >= self.msDrawAgain:
|
||||
for client in self.game.rgclient:
|
||||
for client in self.game.rgclientActive:
|
||||
ascr = ansi.Ascr()
|
||||
for tok in self.game.rgtoken("drawable", self.rgprio):
|
||||
try:
|
||||
|
@ -552,8 +606,8 @@ class Token(Taggable):
|
|||
def runI(self):
|
||||
try:
|
||||
self.run()
|
||||
#except greenlet.GreenletExit:
|
||||
# raise
|
||||
except greenlet.GreenletExit:
|
||||
raise
|
||||
except Exception:
|
||||
print "token script crashed:"
|
||||
traceback.print_exc()
|
||||
|
|
7
inspector.py
Normal file
7
inspector.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
# to use:
|
||||
# python -i inspector.py
|
||||
# >>> i.Rgclass() ...
|
||||
from whiteboard import *
|
||||
|
||||
o = tpers.Odb.Load('whiteboard.marm')
|
||||
i = tpers.StaticIndex().Populate(o)
|
15
scripting.py
15
scripting.py
|
@ -28,9 +28,10 @@ def RegStmt(clsStmt):
|
|||
class Botdef(TPrs):
|
||||
def InitPersistent(self, stName, ach, x, y):
|
||||
self.stName = stName
|
||||
self.ast = ast
|
||||
self.ach = ach
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.fPlayer = False
|
||||
self.syntOnTouch = SyntBlock()
|
||||
|
||||
class Flagdef(TPrs):
|
||||
|
@ -62,6 +63,9 @@ class Vm(TPrs):
|
|||
def FFlagSet(self, flagdef):
|
||||
return self.mpflagdef[flagdef]
|
||||
|
||||
def Fail(self, stMessage, synt):
|
||||
self.Log(Fail(stMessage, synt))
|
||||
|
||||
def Log(self, fail):
|
||||
print(fail.stMessage, fail.synt)
|
||||
|
||||
|
@ -155,7 +159,7 @@ class Synt(Typeable):
|
|||
pass
|
||||
def Eval(self, vm):
|
||||
"Execute yourself, in the context of vm."
|
||||
return Fail("Missing information", self)
|
||||
return vm.Fail("Missing information", self)
|
||||
|
||||
def StypeForChild(self, syntChild):
|
||||
"Return the stype that should be applied to the given child."
|
||||
|
@ -361,7 +365,7 @@ class SyntFlagRef(Synt):
|
|||
try:
|
||||
return vm.FFlagSet(self.flagdef)
|
||||
except:
|
||||
return Fail("No such flag", self)
|
||||
return vm.Fail("No such flag", self)
|
||||
|
||||
class SyntIsFlagSet(SyntDesc):
|
||||
desc = [["set"]]
|
||||
|
@ -422,10 +426,9 @@ class Fail(TPrs):
|
|||
edit a script while the game is running and see the effect of their changes immediately; this suggests that failures
|
||||
should be logged and the script should continue to run.
|
||||
"""
|
||||
def InitPersistent(self, vm, stFailure, synt):
|
||||
def InitPersistent(self, stFailure, synt):
|
||||
self.stFailure = stFailure
|
||||
self.synt = synt
|
||||
vm.Log(self)
|
||||
|
||||
# projection cursor
|
||||
class Pcur(object):
|
||||
|
@ -880,7 +883,7 @@ class Pov(TokenClient):
|
|||
|
||||
def run(self):
|
||||
while True:
|
||||
key = self.client.evKey.receive(self)
|
||||
key = self.client.EvKey(self.game).receive(self)
|
||||
if key == ansi.K_PGDN:
|
||||
self.block.Eval(Vm(self.defs))
|
||||
psel = self.pselstate.PselByClient(self.client)
|
||||
|
|
12
telnet.py
12
telnet.py
|
@ -41,8 +41,6 @@ class AnsiTelnet(protocol.Protocol):
|
|||
print "created"
|
||||
self.ast = None
|
||||
self.client = client
|
||||
self.evKey = None
|
||||
self.evArrow = None
|
||||
self.Refresh()
|
||||
|
||||
def connectionMade(self):
|
||||
|
@ -122,28 +120,22 @@ class AnsiTelnet(protocol.Protocol):
|
|||
print "negotiated!"
|
||||
self.transport.write(ansi.esc + "2J") #cls
|
||||
self.transport.write(ansi.esc + "=25l") #hide the cursor
|
||||
self.client.dgJoinGame = self.CreateEvents
|
||||
self.client.addDgQuit(self.transport.loseConnection)
|
||||
self.client.go(self.factory.fnRun, self)
|
||||
|
||||
def RcvText(self, text):
|
||||
if self.client.evKey:
|
||||
for ch in text:
|
||||
self.client.evKey.fire(ch)
|
||||
self.client.KeyPressed(ch)
|
||||
|
||||
mpcode_key = {"A": ansi.K_UP, "B": ansi.K_DOWN, "C": ansi.K_RIGHT, "D": ansi.K_LEFT,
|
||||
"K": ansi.K_END, "H": ansi.K_HOME, "V": ansi.K_PGUP, "U": ansi.K_PGDN }
|
||||
|
||||
def RcvAnsi(self, code, rgarg):
|
||||
if self.client.evKey:
|
||||
if code in self.mpcode_key:
|
||||
self.client.evKey.fire(self.mpcode_key[code])
|
||||
self.client.KeyPressed(self.mpcode_key[code])
|
||||
else:
|
||||
print "unrecognized code", code, rgarg
|
||||
|
||||
def CreateEvents(self, client, game):
|
||||
client.evKey = engine.Event(game)
|
||||
|
||||
def Draw(self, ascr):
|
||||
self.transport.write(self.ascr.AstDiff(ascr))
|
||||
self.transport.write(ansi.esc + "H") #cursor stays in top-left corner? ascr should contain a cursor pos?
|
||||
|
|
58
tpers.py
58
tpers.py
|
@ -319,3 +319,61 @@ def _unpickle_method(func_name, obj, cls):
|
|||
import copy_reg
|
||||
import types
|
||||
copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)
|
||||
|
||||
def hashable(v):
|
||||
try:
|
||||
hash(v)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
class StaticIndex(TPrs):
|
||||
def InitPersistent(self, fIncludeTemp = False):
|
||||
self.mpv_a_rge = {}
|
||||
self.rgv = set()
|
||||
self.fIncludeTemp = fIncludeTemp
|
||||
|
||||
def FPersist(self):
|
||||
return False
|
||||
|
||||
def AddEAV(self, e, a, v):
|
||||
if v not in self.mpv_a_rge:
|
||||
self.mpv_a_rge[v] = {}
|
||||
a_rge = self.mpv_a_rge[v]
|
||||
if a not in a_rge:
|
||||
a_rge[a] = []
|
||||
a_rge[a].append(e)
|
||||
|
||||
def Populate(self, v, a = (), e = None):
|
||||
if hashable(v):
|
||||
if e:
|
||||
self.AddEAV(e, a, v)
|
||||
if v in self.rgv:
|
||||
return self
|
||||
self.rgv.add(v)
|
||||
if isinstance(v, TPrs):
|
||||
attrs = set(v._persistent.keys())
|
||||
if self.fIncludeTemp:
|
||||
attrs = attrs.union(set(v.__dict__.keys()))
|
||||
for attr in attrs:
|
||||
child = getattr(v, attr)
|
||||
self.Populate(child, (attr,), v)
|
||||
elif isinstance(v, clsList) or isinstance(v, clsTuple):
|
||||
for ichild, child in enumerate(v):
|
||||
self.Populate(child, a + (ichild,), e)
|
||||
elif isinstance(v, clsSet):
|
||||
for child in v:
|
||||
self.Populate(child, a, e)
|
||||
elif isinstance(v, clsDict):
|
||||
for k, child in v.items():
|
||||
self.Populate(child, a + (k,), e)
|
||||
return self
|
||||
|
||||
def Rgclass(self):
|
||||
return set([v.__class__ for v in self.rgv])
|
||||
|
||||
def RgvWithClass(self, cls):
|
||||
return [v for v in self.rgv if isinstance(v, cls)]
|
||||
|
||||
def Rgref(self, v):
|
||||
return self.mpv_a_rge.get(v)
|
||||
|
|
180
whiteboard.py
180
whiteboard.py
|
@ -20,6 +20,7 @@ from basetoken import *
|
|||
from tpers import *
|
||||
from datetime import *
|
||||
from util import *
|
||||
from scripting import Botdef, Flagdef, Defs, PselState, Pov
|
||||
import telnet
|
||||
import time
|
||||
import login
|
||||
|
@ -129,8 +130,13 @@ class Drawing(Ownable):
|
|||
def SetTimestamp(self):
|
||||
self.dtLastModified = datetime.now()
|
||||
|
||||
@Version(3)
|
||||
@Version(4)
|
||||
class Board(Drawing):
|
||||
def InitPersistent(self, owner, stName, user, rglayer=None, dtLastModified=None):
|
||||
super(Board, self).InitPersistent(owner, stName, user, rglayer=rglayer, dtLastModified=dtLastModified)
|
||||
self.defs = Defs()
|
||||
self.layerObj = self.rglayer[0]
|
||||
|
||||
def StType(self):
|
||||
return "Board"
|
||||
def W(self): return config.W
|
||||
|
@ -140,6 +146,10 @@ class Board(Drawing):
|
|||
for layer in reversed(self.rglayer):
|
||||
ascr.PutAscr(layer.ascr)
|
||||
|
||||
def DrawObjectDefs(self, ascr):
|
||||
for botdef in self.defs.rgbotdef:
|
||||
ascr.PutAch(botdef.ach, botdef.x, botdef.y)
|
||||
|
||||
def Save(self):
|
||||
fn = config.DIR_ANSI + "/" + "_".join([str(x) for x in time.localtime()])
|
||||
ascr = ansi.Ascr(self.W(), self.H())
|
||||
|
@ -158,6 +168,9 @@ class Board(Drawing):
|
|||
self.user = gameWB.user
|
||||
if versionOld < 3:
|
||||
self.chat = Chat()
|
||||
if versionOld < 4:
|
||||
self.defs = Defs()
|
||||
self.layerObj = self.rglayer[0]
|
||||
|
||||
class Sprite(Drawing):
|
||||
def InitPersistent(self, owner, stName, user, w, h):
|
||||
|
@ -225,17 +238,20 @@ class Chat(TPrs):
|
|||
def InitTransient(self):
|
||||
TPrs.InitTransient(self)
|
||||
self.cchl = 100
|
||||
self.DetachFromGame()
|
||||
self.MakeTransient("game", None)
|
||||
self.MakeTransient("evChat", None)
|
||||
|
||||
def InitPersistent(self):
|
||||
TPrs.InitPersistent(self)
|
||||
self.rgchl = []
|
||||
|
||||
def AttachToGame(self, game):
|
||||
with self.SetTransiently():
|
||||
self.game = game
|
||||
self.evChat = Event(game)
|
||||
|
||||
def DetachFromGame(self):
|
||||
with self.SetTransiently():
|
||||
self.game = None
|
||||
self.evChat = None
|
||||
|
||||
|
@ -248,8 +264,10 @@ class Chat(TPrs):
|
|||
|
||||
def CChl(self):
|
||||
return len(self.rgchl)
|
||||
|
||||
def CUsers(self):
|
||||
return len(self.game.rgclient)
|
||||
return len(self.game.RgclientConnected())
|
||||
|
||||
def DrawMsg(self, ascr, x, y, w, h, colBg=ansi.BLACK, ichl=0):
|
||||
yDraw = y + h - 1
|
||||
for chl in self.rgchl[ichl:]:
|
||||
|
@ -274,8 +292,8 @@ class Chat(TPrs):
|
|||
|
||||
def DrawUsers(self, ascr, x, y, w, h, colBg=ansi.BLACK, iuser=0):
|
||||
yDraw = y
|
||||
for client in sorted(self.game.rgclient, lambda c1, c2: cmp(c1.Cldg().iclient, c2.Cldg().iclient))[iuser:]:
|
||||
ascr.PutSt("{0:{1}}".format(str(client.Cldg().iclient) + ") " + client.cld.user, w), x, yDraw, ansi.WHITE, colBg)
|
||||
for client in sorted(self.game.RgclientConnected(), lambda c1, c2: cmp(c1.Cldg(self.game).iclient, c2.Cldg(self.game).iclient))[iuser:]:
|
||||
ascr.PutSt("{0:{1}}".format(str(client.Cldg(self.game).iclient) + ") " + client.cld.user, w), x, yDraw, ansi.WHITE, colBg)
|
||||
yDraw = yDraw + 1
|
||||
if yDraw == y + h:
|
||||
break
|
||||
|
@ -320,19 +338,38 @@ class Cursor(TokenClient):
|
|||
miQuit = MiButton("Back to Menu", self.client.leaveGame)
|
||||
self.cf = self.MenuDrawing(miFg, miBg, miChars, miQuit)
|
||||
self.miChat = MiMenu([None, MiChat(self.client, 13, self.game.drawing.chat), MiTypein(self.SendMsg), None, miQuit, None])
|
||||
self.rgmiLayer = RgmiProjected(self.game.drawing.rglayer, DgProjectMiButton(self.SelectLayer))
|
||||
self.rgmiLayer = RgmiProjected(self.game.drawing.rglayer, DgProjectMiButton(self.SelectLayer, self.StLayerName))
|
||||
self.miLayers = self.MenuLayers(miQuit)
|
||||
self.ovPopup = OvPopup(self, self.client, MiTab.MiTabbed(["Drawing", self.cf], [self.StLayerTab(), self.miLayers], ["Chat", self.miChat]))
|
||||
miStatus = MiMenuHoriz([MiStatic("Hit <Tab> for menu"), MiValue(miChars)])
|
||||
miStatus = MiMenuHoriz([MiDgText(self.StStatus), MiValue(miChars)])
|
||||
miStatus.ListenForNotice(self.miChat)
|
||||
self.ovStatus = OvStatic(self, self.client, miStatus, OvStatic.BOTTOM)
|
||||
|
||||
def StLayerName(self, layer):
|
||||
return ('[Bot] ' if layer == self.game.drawing.layerObj else '') + layer.StName()
|
||||
|
||||
def StStatus(self):
|
||||
stStatus = "<Tab>: Menu"
|
||||
if self.GetLayer() == self.game.drawing.layerObj:
|
||||
botdef = self.BotdefAtPos(self.pos)
|
||||
if botdef:
|
||||
stStatus += " | <Enter>: Edit bot"
|
||||
elif self.game.drawing.layerObj.ascr.GetAch(self.pos.X(), self.pos.Y()) != ansi.achBlank:
|
||||
stStatus += " | <Enter>: Make bot"
|
||||
return stStatus
|
||||
|
||||
def BotdefAtPos(self, pos):
|
||||
for botdef in self.game.drawing.defs.rgbotdef:
|
||||
if botdef.x == pos.X() and botdef.y == pos.Y():
|
||||
return botdef
|
||||
|
||||
def MenuDrawing(self, miFg, miBg, miChars, miQuit):
|
||||
return MiMenu([None, miFg, miBg, None, miChars, None, MiButton("Save", self.Save), None, miQuit, None])
|
||||
|
||||
def MenuLayers(self, miQuit):
|
||||
return MiMenu(Rgseq([None], self.rgmiLayer, [None, MiButton("New Layer", self.NewLayer), MiButton("Move up", self.LayerUp), MiButton("Move down", self.LayerDown),
|
||||
None, MiToggle("Show One"), None, MiStatic("Rename selected layer:"), MiTypein(self.RenameLayer, "LayerName", 80), None, miQuit, None]))
|
||||
None, MiToggle("Show One"), MiButton("Set as bot layer", self.SetBotLayer), None,
|
||||
MiStatic("Rename selected layer:"), MiTypein(self.RenameLayer, "LayerName", 80), None, miQuit, None]))
|
||||
def StLayerTab(self): return "Layers"
|
||||
def Save(self):
|
||||
self.game.drawing.Save()
|
||||
|
@ -345,7 +382,8 @@ class Cursor(TokenClient):
|
|||
return True
|
||||
|
||||
def GetLayer(self):
|
||||
return self.ovPopup.GetSelection("layer").Value()
|
||||
selLayer = self.ovPopup.GetSelection("layer")
|
||||
return selLayer.Value().Value() if selLayer else None
|
||||
|
||||
def NewLayer(self):
|
||||
ilayer = 1
|
||||
|
@ -373,6 +411,9 @@ class Cursor(TokenClient):
|
|||
self.GetLayer().SetName(st)
|
||||
return True
|
||||
|
||||
def SetBotLayer(self):
|
||||
self.game.drawing.layerObj = self.GetLayer()
|
||||
|
||||
def blinkCursor(self, fBlink):
|
||||
self.fBlink = fBlink
|
||||
if not fBlink and self.cDontBlink > 0:
|
||||
|
@ -391,7 +432,7 @@ class Cursor(TokenClient):
|
|||
def run(self):
|
||||
with self.game.drawing.chat.evChat.oob(self, self.OnChat):
|
||||
while True:
|
||||
key = self.client.evKey.receive(self)
|
||||
key = self.client.EvKey(self.game).receive(self)
|
||||
fDontBlink = True
|
||||
if key == ansi.K_LEFT:
|
||||
self.pos.Left()
|
||||
|
@ -419,6 +460,8 @@ class Cursor(TokenClient):
|
|||
self.Skip(self.pos.Up)
|
||||
elif key == ansi.K_PGDN:
|
||||
self.Skip(self.pos.Down)
|
||||
elif key == ansi.K_NEWLINE or key == ansi.K_RETURN:
|
||||
self.EditBot()
|
||||
elif ansi.FKeyPrintable(key):
|
||||
if key.isdigit():
|
||||
self.PutWb(chr(self.cf.Value("Characters")[IchFromCh(key)]))
|
||||
|
@ -466,6 +509,41 @@ class Cursor(TokenClient):
|
|||
def FDrawCursor(self):
|
||||
return self.fBlink or self.cDontBlink > 0
|
||||
|
||||
def EditBot(self):
|
||||
if self.GetLayer() == self.game.drawing.layerObj:
|
||||
botdef = self.BotdefAtPos(self.pos)
|
||||
ach = self.game.drawing.layerObj.ascr.GetAch(self.pos.X(), self.pos.Y())
|
||||
fNewBot = ach != ansi.achBlank if not botdef else False
|
||||
if not fNewBot and not botdef:
|
||||
return
|
||||
if fNewBot:
|
||||
botdef = Botdef('Bot ' + str(len(self.game.drawing.defs.rgbotdef) + 1) + ' (' + ansi.Ach(ach).ch + ')', ach, self.pos.X(), self.pos.Y())
|
||||
|
||||
evDone = Event(self.game)
|
||||
def DgDone(val):
|
||||
return lambda: evDone.fire(val)
|
||||
|
||||
miBotName = MiTypein(None, "BotName", 80)
|
||||
miBotName.SetValue(botdef.stName)
|
||||
miMenu = MiMenu([None,
|
||||
MiStatic("Bot Name"), miBotName, None,
|
||||
MiToggle("Is Player", botdef.fPlayer), None,
|
||||
MiButton("Save", DgDone(True)), MiButton("Cancel", DgDone(False)), None,
|
||||
MiButton("Edit Code (live)", lambda: self.client.joinGame(self.game.GameSyntEdit(botdef.syntOnTouch))), None])
|
||||
|
||||
ov = OvMenu(self, self.client, miMenu, OvMenu.MIDDLE)
|
||||
try:
|
||||
result = evDone.receive(self)
|
||||
finally:
|
||||
ov.die()
|
||||
if result:
|
||||
botdef.stName = miBotName.Value()
|
||||
botdef.fPlayer = miMenu.MiByName("Is Player").Value()
|
||||
if fNewBot:
|
||||
self.game.drawing.defs.rgbotdef.append(botdef)
|
||||
|
||||
|
||||
|
||||
def draw(self, ascr, client):
|
||||
if self.FDrawCursor():
|
||||
if client == self.client:
|
||||
|
@ -475,7 +553,7 @@ class Cursor(TokenClient):
|
|||
chCursor = chr(177)
|
||||
self.Put(chCursor, ascr, *self.XzYzScreenPic())
|
||||
elif self.fBlink:
|
||||
self.Put(str(self.client.Cldg().iclient)[0], ascr, *self.XzYzScreenPic())
|
||||
self.Put(str(self.client.Cldg(self.game).iclient)[0], ascr, *self.XzYzScreenPic())
|
||||
|
||||
class CursorSprite(Cursor):
|
||||
def InitPersistent(self, game, client):
|
||||
|
@ -492,7 +570,9 @@ class CursorSprite(Cursor):
|
|||
return MiMenu(Rgseq([None], self.rgmiLayer, [None, MiButton("New Frame", self.NewLayer), MiButton("Move up", self.LayerUp), MiButton("Move down", self.LayerDown),
|
||||
None, MiStatic("Rename selected frame:"), MiTypein(self.RenameLayer, "LayerName", 80), None, MiButton("Animate", self.Animate), None, miQuit, None]))
|
||||
|
||||
def StStatus(self): return "Hit <Tab> for menu"
|
||||
def StLayerTab(self): return "Frames"
|
||||
|
||||
def NewLayer(self):
|
||||
stLayer = "Frame " + str(len(self.game.drawing.rglayer) + 1)
|
||||
layer = self.GetLayer()
|
||||
|
@ -521,10 +601,14 @@ class WhiteboardDraw(TokenClient):
|
|||
|
||||
def draw(self, ascr, client):
|
||||
if client == self.client:
|
||||
fDrawObjects = True
|
||||
if self.owner.miLayers.Value("Show One"):
|
||||
ascr.PutAscr(self.owner.GetLayer().ascr)
|
||||
fDrawObjects = self.owner.GetLayer() == self.owner.layerObj
|
||||
else:
|
||||
self.game.drawing.draw(ascr)
|
||||
if fDrawObjects:
|
||||
self.game.drawing.DrawObjectDefs(ascr)
|
||||
|
||||
class SpriteDraw(TokenClient):
|
||||
def InitPersistent(self, owner, client):
|
||||
|
@ -671,10 +755,10 @@ class Joiner(LeaveJoinToken):
|
|||
self.board = self.game.drawing
|
||||
|
||||
def OnJoin(self, client):
|
||||
with client.Cldg().SetTransiently() as cldg:
|
||||
with client.Cldg(self.game).SetTransiently() as cldg:
|
||||
cldg.iclient = -1
|
||||
iclient = 1
|
||||
rgiclient = [clientT.Cldg().iclient for clientT in self.game.rgclient]
|
||||
rgiclient = [clientT.Cldg(self.game).iclient for clientT in self.game.RgclientConnected()]
|
||||
while iclient in rgiclient:
|
||||
iclient = iclient + 1
|
||||
cldg.iclient = iclient
|
||||
|
@ -813,7 +897,29 @@ class GameLogin(Game):
|
|||
def GetRgclsTokTrans(self):
|
||||
return [[AutoJoiner, login.LoginTerm]]
|
||||
|
||||
@Version(6)
|
||||
class Mpsubgame(TPrs):
|
||||
def InitPersistent(self, game, dgMakeGame):
|
||||
self.game = game
|
||||
self.dgMakeGame = dgMakeGame
|
||||
self.mpkey_subgame = {}
|
||||
|
||||
def SubgameFromKey(self, key):
|
||||
if not (key in self.mpkey_subgame):
|
||||
subgame = self.dgMakeGame(key)
|
||||
subgame.rgdgdie.append(Partial(self.KillSubgame, key))
|
||||
self.mpkey_subgame[key] = subgame
|
||||
return self.mpkey_subgame[key]
|
||||
|
||||
def KillSubgame(self, key):
|
||||
del self.mpkey_subgame[key]
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.mpkey_subgame
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.mpkey_subgame[key]
|
||||
|
||||
@Version(7)
|
||||
class GameLobby(Game):
|
||||
def InitPersistent(self):
|
||||
self.rgproject = []
|
||||
|
@ -821,30 +927,37 @@ class GameLobby(Game):
|
|||
|
||||
def InitTransient(self):
|
||||
Game.InitTransient(self)
|
||||
self.mpdrawing_game = {}
|
||||
self.mpdrawing_game = Mpsubgame(self, self.MakeGameFromDrawing)
|
||||
self.mpdrawingsynt_game = Mpsubgame(self, self.MakeGameSyntEdit)
|
||||
|
||||
def GetRgclsTokTrans(self):
|
||||
return [[AutoJoiner, Lobby]]
|
||||
|
||||
def GameFromDrawing(self, drawing):
|
||||
if not (drawing in self.mpdrawing_game):
|
||||
return self.mpdrawing_game.SubgameFromKey(drawing)
|
||||
|
||||
def MakeGameFromDrawing(self, drawing):
|
||||
if drawing.StType() == "Board":
|
||||
game = GameWB(self, drawing)
|
||||
return GameWB(self, drawing)
|
||||
elif drawing.StType() == "Sprite":
|
||||
game = GameSprEdit(self, drawing)
|
||||
return GameSprEdit(self, drawing)
|
||||
else:
|
||||
assert False, "Lobby not prepared to deal with drawing of type " + drawing.StType()
|
||||
game.rgdgdie.append(Partial(self.KillBoard, drawing))
|
||||
self.mpdrawing_game[drawing] = game
|
||||
return game
|
||||
return self.mpdrawing_game[drawing]
|
||||
|
||||
# we accidentally persisted references to this method that are immediately removed by Chat.InitTransient()
|
||||
def KillBoard(self, drawing):
|
||||
del self.mpdrawing_game[drawing]
|
||||
pass
|
||||
|
||||
def GameFromSynt(self, drawing, synt):
|
||||
return self.mpdrawingsynt_game.SubgameFromKey((drawing, synt))
|
||||
|
||||
def MakeGameSyntEdit(self, drawing_synt):
|
||||
drawing, synt = drawing_synt
|
||||
return GameSyntEdit(drawing, synt)
|
||||
|
||||
def CclientDrawing(self, drawing):
|
||||
if drawing in self.mpdrawing_game:
|
||||
return len(self.mpdrawing_game[drawing].rgclient)
|
||||
return len(self.mpdrawing_game[drawing].RgclientConnected())
|
||||
return 0
|
||||
|
||||
def StNameProject(self, project):
|
||||
|
@ -883,7 +996,12 @@ class GameLobby(Game):
|
|||
project.rgdrawing.append(board)
|
||||
del self.rgboard
|
||||
self.rgproject = [project]
|
||||
self.mpuser_cldg = {} # ugh, upgrading parent classes is broken in our model :(
|
||||
|
||||
# ugh, upgrading parent classes is broken in our model :(
|
||||
if versionOld < 6:
|
||||
Game.UpgradeFrom(self, 1)
|
||||
elif versionOld < 7:
|
||||
Game.UpgradeFrom(self, 2)
|
||||
|
||||
class GameWB(Game):
|
||||
def InitPersistent(self, gameLobby, board):
|
||||
|
@ -906,6 +1024,18 @@ class GameWB(Game):
|
|||
def GetRgtagDraw(self):
|
||||
return ["background", "solid", "cursor", "menu", "msgscroller"]
|
||||
|
||||
def GameSyntEdit(self, synt):
|
||||
return self.gameLobby.GameFromSynt(self.drawing, synt)
|
||||
|
||||
class GameSyntEdit(Game):
|
||||
def InitPersistent(self, board, synt):
|
||||
Game.InitPersistent(self)
|
||||
self.board = board
|
||||
self.synt = synt
|
||||
|
||||
def GetRgclsTokTrans(self):
|
||||
return [[PselState, self.board.defs, self.synt], [AutoJoiner, [Pov, self.board.defs, self.synt]]]
|
||||
|
||||
class GameSprEdit(GameWB):
|
||||
def ClsCursor(self):
|
||||
return CursorSprite
|
||||
|
|
Loading…
Reference in a new issue