marmots/scripting.py

711 lines
26 KiB
Python
Raw Normal View History

2011-03-19 00:10:02 +00:00
from engine import *
from basetoken import *
from tpers import *
from util import *
# scope -- a block? a scril? (scril lets you specifically avoid vars that are defined after a certain point) + game?
# method: rgvar(stype) -- returns a list of variables in scope that match the current stype
# var -- a variable
# contains: stype, sargInitializer
# a var IS A SCRIL
# the scmd creates a new vari in the current ectx, and adds the scril to a map of things that refer to it
# sproj -- an object that can project a sarg into an pw
# stypes should be sprojectors and express a default projection as a class method (why?)
# MiSarg -- an editor for sargs
# MiSargNum, MiSargDrop
# MiScriptLine -- projects a scriptline
# sobj -- generic hungarian for any object that is usable in scripts
# fail -- a FAILURE OBJECT; if it is used as a sarg when evaluating an scmd, a failure is logged and the scmd returns fail.
# execution:
# ectx -- execution context
# contains: mpvar_sobj
# block
# iscril (selection?)
# ectxReturn
# methods: call(block)
class Block(TPrs):
def InitPersistent(self, scrilParent):
self.rgscril = []
self.scrilParent = scrilParent
def InsertScrilAfter(self, scrilAfter, scmd = None):
scrilNew = Scril(self, scmd)
if scrilAfter == None:
self.rgscril.insert(0, scrilNew)
else:
self.rgscril.insert(self.rgscril.index(scrilAfter) + 1, scrilNew)
return scrilNew
def Project(self, pwBlock, dxIndent = 0):
if pwBlock == None:
pwBlock = PwBlock(None, self, 0)
PwButtonHidden(pwBlock, "[insert new line]", None, self.InsertScrilAfter, dxIndent)
for scril in self.rgscril:
scril.Project(pwBlock, dxIndent)
return pwBlock
class Typeable(TPrs):
def InitTransient(self):
self.steditTypein = Stedit()
def GetStTypein(self):
st = self.steditTypein.GetValue()
return None if st == "" else st
def SetStTypein(self, stTypein):
self.steditTypein.SetValue(stTypein or "")
def HandleTypeinKey(self, key):
return self.steditTypein.HandleKey(key)
# Sarg -- pointer to scripting object / argument to a command
# this object type appears to exist solely so that MiSarg can edit something without digging through a list
class Sarg(Typeable):
def InitPersistent(self, stype, scril):
self.stype = stype
self.sobj = stype.SobjDefault(scril)
def FExpr(self):
"Returns true if the sobj must be evaluated to get a result."
return self.sobj.__class__ == Scril
def Eval(self, ectx):
if self.FExpr():
return self.sobj.Exec(ectx)
else:
return self.sobj
class Fail(TPrs):
def InitPersistent(self, stFailure):
self.stFailure == stFailure
# stype -- a description of a sobj (scripting object)
# method: FMember(sobj) -- returns true if an object is in the set of things that this stype represents
# method: FOverlaps(stype) -- returns true if there is some overlap between the two stypes
# -- there is no subtype/supertype relation because stypes are used to help the user,
# and I suspect being specific in this manner is too much of a burden to place on them.
# methods: rgsarg(scope) -- returns a list of all legal objects that exist in the current scope
# this includes functions which return things of this stype, and variables
# literals are not included
# project(cls, game, sarg) -- returns an MiSarg which displays and edits (default sproj for a sarg?)
class Stype(object):
"""A definition of a scripting object type. All methods are class methods; stypes are never instantiated."""
def __init__(self):
raise "do not instantiate stypes"
@classmethod
def FMember(cls, sobj):
return isinstance(sobj, cls.pythontype)
@classmethod
def FOverlaps(cls, stype):
return stype == self
@classmethod
def Rgsobj(cls, scope):
return []
@classmethod
def Rgsobj_st(cls, scope):
return [(sobj, str(sobj)) for sobj in cls.Rgsobj(scope)]
@classmethod
def OnSelect(cls, sarg, sobj):
sarg.sobj = sobj
@classmethod
def Sproj(cls, sarg, pwBlock, pwScril):
ProjectTypein(pwScril, sarg, str(sarg.sobj), cls.Rgsobj_st, cls.OnSelect)
return False
def ProjectTypein(pwParent, typeable, st, dgRgsobj_st, dgOnSelect):
def OnSelect(sobj):
dgOnSelect(typeable, sobj)
typeable.SetStTypein(None)
if typeable.GetStTypein() != None:
pwParent = PwDropdown(pwParent)
PwTypein(pwParent, st, typeable)
if typeable.GetStTypein() != None:
for sobj, st in dgRgsobj_st(typeable):
PwButton(pwParent, st, sobj, OnSelect)
class StypeBool(Stype):
pythontype = bool
@classmethod
def SobjDefault(cls, scril):
return False
@classmethod
def Rgsobj(cls, scope):
return [True, False]
class StypeBlock(Stype):
pythontype = Block
@classmethod
def SobjDefault(cls, scril):
return Block(scril)
@classmethod
def Sproj(cls, sarg, pwBlock, pwScril):
sarg.sobj.Project(pwBlock, pwScril.DxIndent() + 2)
return True
# scmd -- a definition of a scripting command
class Scmd(object):
"""A definition of a scripting command. All methods are class methods; scmds are never instantiated."""
def __init__(self):
raise "do not instantiate scmds"
# used by RegScmd to build a list of all valid scmds for editing
rgscmd = []
@classmethod
def Rgscmd_st(cls, scril):
return [(scmd, scmd.StName()) for scmd in cls.rgscmd]
@classmethod
def Desc(cls, *rgsarg):
"""
Returns a list of desces. A desce can be a constant string, representing nonselectable helper text,
an sproj, a list containing an sproj and a reference to a passed-in sarg, which explicitly binds that
sproj to that sarg, or a list containing a string, which stands for the selectable text which represents
the scril itself.
ie, [["Move"], " ", [SprojMovable, rgsarg[1]], " to ", [SprojPosition, rgsarg[0]]]
If a bare sproj is given, bind it to the first unbound sarg (after processing all explicitly bound sargs).
This method must accept invalid sargs; it is the sproj's job to relay the invalidness to the user.
"""
return cls.desc
stName = None
@classmethod
def StName(cls):
"Returns the name that the user types in to select this scmd."
if cls.stName != None:
return cls.stName
for desce in cls.Desc(Scril(None, cls).rgsarg):
if type(desce) == list and type(desce[0]) == str:
return desce[0]
assert False, "no selectable self in desc"
@classmethod
def Csarg(cls):
"Returns the number of arguments that this command takes."
return len(cls.rgstypeArg)
@classmethod
def StypeResult(cls):
return cls.stypeResult
@classmethod
def RgstypeArg(cls):
return cls.rgstypeArg
def RegScmd(stypeResult, *rgstypeArg):
def RegI(cls):
cls.stypeResult = stypeResult
cls.rgstypeArg = rgstypeArg
Scmd.rgscmd.append(cls)
return cls
return RegI
@RegScmd(None)
class ScmdBlank(Scmd):
stName = ""
desc = [[" "]]
@classmethod
def Exec(cls, ectx):
pass
@RegScmd(None)
class ScmdHelloWorld(Scmd):
"Hello, world!"
desc = [["Hello World"], "!"]
@classmethod
def Exec(cls, ectx):
print "Hello, world!"
@RegScmd(None, StypeBool, StypeBlock, StypeBlock)
class ScmdIf(Scmd):
desc = [["If"], " ", StypeBool.Sproj, ", then:", StypeBlock.Sproj, "or else:", StypeBlock.Sproj]
@classmethod
def Exec(cls, ectx, sargExpr, sargIfTrue, sargIfFalse):
if sargExpr.Eval(ectx):
print "true!"
# needs work
#===========================================================================
# @RegScmd(None, StypeSt, StypeObj)
# class ScmdVar(Scmd):
# desc = ["Define a new ", ["variable"], " called \"", StypeSt, "\", set to ", StypeObj, "."]
# @classmethod
# def Exec(cls, ectx, sargStName, sargInit):
# ectx.mpvar_sobj[ectx.ScrilCurr()] = sargInit.Eval()
#===========================================================================
class Scril(Typeable):
"A line in a script."
def InitPersistent(self, blockParent, scmd = None):
self.scmd = scmd or ScmdBlank
self.rgsarg = [Sarg(stypeArg, self) for stypeArg in self.scmd.RgstypeArg()]
self.blockParent = blockParent
def SetScmd(self, scmd):
if (scmd.Csarg() > self.scmd.Csarg()):
self.rgsarg.extend([Sarg(stypeArg, self) for stypeArg in scmd.RgstypeArg()[self.scmd.Csarg():]])
elif (scmd.Csarg() < self.scmd.Csarg()):
self.rgsarg = self.rgsarg[:scmd.Csarg()]
self.scmd = scmd
def Exec(self, ectx):
return self.scmd.Exec(ectx, *self.rgsarg)
def HandleKey(self, pwKey, pov, psel, key):
if ansi.FEnter(key):
self.blockParent.InsertScrilAfter(self, ScmdBlank)
return True
return False
def Project(self, pwBlock, dxindent):
"adds horizontal pws to a vertical pw"
pwScril = None
desc = self.scmd.Desc(*self.rgsarg)
rgsargUnbound = list(self.rgsarg)
#filter bound sargs
for desce in desc:
if isinstance(desce, list) and len(desce) > 1:
rgsargUnbound.remove(desce[1])
fNewScril = True
for desce in desc:
if fNewScril:
pwKey = PwKeyHandler(pwBlock, self.HandleKey)
pwScril = PwList(pwKey, self, dxindent)
fNewScril = False
if isinstance(desce, str):
PwStatic(pwScril, desce)
elif isinstance(desce, list):
if isinstance(desce[0], str):
# selection for the scmd / scril
ProjectTypein(pwScril, self, desce[0], Scmd.Rgscmd_st, Scril.SetScmd)
else:
# mapping to sarg
fNewScril = self.ProjectSarg(pwBlock, pwScril, desce[0], desce[1])
else:
# sproj
fNewScril = self.ProjectSarg(pwBlock, pwScril, desce, rgsargUnbound.pop(0))
def ProjectSarg(self, pwBlock, pwScril, sproj, sarg):
return sproj(sarg, pwBlock, pwScril)
# pw - projected widget
# Nothing ever depends on the object identity or permanence of a pw!
# They are generated on demand, whenever we need to draw or process a
# keypress.
class Pw(object):
def __init__(self, pwParent):
if pwParent != None:
pwParent.AddChild(self)
self.pwParent = pwParent
def PwParent(self):
return self.pwParent
def Value(self):
return None
def FSelectable(self):
return False
def FContainer(self):
return False
def RgpwChild(self):
return []
def HandleKey(self, pov, psel, key):
return False
def PwFirstSelectable(self):
if self.FSelectable():
return self
for pwChild in self.RgpwChild():
pw = pwChild.PwFirstSelectable()
if pw != None:
return pw
return None
class PwContainer(Pw):
def __init__(self, pwParent):
Pw.__init__(self, pwParent)
self.rgpwContents = []
def AddChild(self, pw):
self.rgpwContents.append(pw)
def RgpwChild(self):
return self.rgpwContents
def FContainer(self):
return True
class PwStatic(Pw):
def __init__(self, pwParent, stText):
Pw.__init__(self, pwParent)
self.stText = stText
def DxDyNew(self, w, dxStart, mpksel):
rgsnippet = self.Rgsnippet(w, dxStart, mpksel)
if len(rgsnippet) == 1:
return (dxStart + len(rgsnippet[0].st), 0)
else:
return (len(rgsnippet[-1].st), len(rgsnippet) - 1)
def StTextDisplay(self, ksel):
return self.stText
def Rgsnippet(self, w, dxStart, mpksel):
ksel = mpksel.Get(self)
return list(RgSnippetWrapped(self.StTextDisplay(ksel), w, ksel == Ksel.NAV, dxStart))
def ColBg(self, ksel):
return ansi.BLACK
def ColFg(self):
return ansi.WHITE | ansi.FBRIGHT
def RgSnippetXY(self, x, y, w, dxStart, mpksel):
fFirst = True
for snippet in self.Rgsnippet(w, dxStart, mpksel):
xT = x + dxStart if fFirst else x
yield (snippet, xT, y)
y = y + 1
fFirst = False
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
if not fOverlay:
ksel = mpksel.Get(self)
for (snippet, x, y) in self.RgSnippetXY(x, y, w, dxStart, mpksel):
ascr.PutSt(snippet.st, x, y, self.ColFg(), self.ColBg(ksel))
class PwTypein(PwStatic):
def __init__(self, pwParent, stSobj, typeable):
if typeable.GetStTypein() == None:
stDisplay = stSobj
else:
stDisplay = None
PwStatic.__init__(self, pwParent, stDisplay)
self.typeable = typeable
def Value(self):
return self.typeable
def StTextDisplay(self, ksel):
if self.stText == None:
return self.typeable.steditTypein.StForSize(ksel == Ksel.NAV)
return self.stText
def FSelectable(self):
return True
def ColBg(self, ksel):
if ksel == Ksel.NAV:
return ansi.YELLOW
elif ksel == Ksel.OTHERNAV:
return ansi.MAGENTA
return ansi.BLUE
def HandleKey(self, pov, psel, key):
return self.typeable.HandleTypeinKey(key)
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
if not fOverlay:
ksel = mpksel.Get(self)
fTextSelect = ksel == Ksel.NAV and self.typeable.GetStTypein() != None
for (snippet, x, y) in self.RgSnippetXY(x, y, w, dxStart, mpksel):
ascr.PutSt(snippet.st, x, y, self.ColFg(), self.ColBg(Ksel.NONE if fTextSelect else ksel))
if fTextSelect:
self.typeable.steditTypein.DrawCursor(ascr, x, y, self.ColFg(), self.ColBg(ksel), snippet)
else:
for pwChild in self.RgpwChild():
pwChild.Draw(ascr, x, y, dxStart, mpksel, fOverlay)
class PwButton(PwStatic):
def __init__(self, pwParent, stText, value, dgEnter):
PwStatic.__init__(self, pwParent, stText)
self.value = value
self.dgEnter = dgEnter
def Value(self):
return self.value
def FSelectable(self):
return True
def ColBg(self, ksel):
if ksel == Ksel.NAV:
return ansi.YELLOW
elif ksel == Ksel.OTHERNAV:
return ansi.MAGENTA
return ansi.BLUE
def ColFg(self):
return ansi.BLUE | ansi.FBRIGHT
def HandleKey(self, pov, psel, key):
if key == ansi.K_RETURN:
self.dgEnter(self.Value())
return True
return False
class PwButtonHidden(PwButton):
def __init__(self, pwParent, stText, value, dgEnter, dxIndent):
PwButton.__init__(self, pwParent, stText, value, dgEnter)
self.dxIndent = dxIndent
def DxDyNew(self, w, dxStart, mpksel):
if mpksel.Get(self) == Ksel.NAV:
return PwButton.DxDyNew(self, w - self.dxIndent, dxStart + self.dxIndent, mpksel)
return (0, 0)
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
if mpksel.Get(self) == Ksel.NAV:
PwButton.Draw(self, ascr, x + self.dxIndent, y, w - self.dxIndent, dxStart, mpksel, fOverlay)
class PwKeyHandler(PwContainer):
def __init__(self, pwParent, dgHandleKey):
PwContainer.__init__(self, pwParent)
self.dgHandleKey = dgHandleKey
def DxDyNew(self, w, dxStart, mpksel):
return self.RgpwChild()[0].DxDyNew(w, dxStart, mpksel)
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
self.RgpwChild()[0].Draw(ascr, x, y, w, dxStart, mpksel, fOverlay)
def HandleKey(self, pov, psel, key):
self.dgHandleKey(self, pov, psel, key)
class PwBlock(PwContainer):
def __init__(self, pwParent, block, dxIndent = 2):
PwContainer.__init__(self, pwParent)
self.block = block
self.dxIndent = dxIndent
def Value(self):
return self.block
def DxIndent(self):
return self.dxIndent
def DxDyNew(self, w, dxStart, mpksel):
return (0, 1 + sum([pw.DxDyNew(w - self.DxIndent(), 0, mpksel)[1] + 1 for pw in self.rgpwContents]))
def RgpwChildToDraw(self):
return self.RgpwChild()
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
for pw in self.RgpwChildToDraw():
pw.Draw(ascr, x + self.DxIndent(), y, w - self.DxIndent(), 0, mpksel, fOverlay)
(dxNew, dyNew) = pw.DxDyNew(w - self.DxIndent(), 0, mpksel)
if dxNew > 0 or dyNew > 0:
y = y + dyNew + 1
def HandleKey(self, pov, psel, key):
if key == ansi.K_UP:
return psel.Dec(self)
elif key == ansi.K_DOWN:
return psel.Inc(self)
elif key == ansi.K_DEL:
pass
return False
class PwDropdown(PwBlock):
def __init__(self, pwParent):
PwBlock.__init__(self, pwParent, None, 0)
def WidthMax(self, mpksel):
w = -1
for pw in self.RgpwChild():
wPw = pw.DxDyNew(1000000, 0, mpksel)[0]
if wPw > w:
w = wPw
return w
def RgpwChildToDraw(self):
return PwBlock.RgpwChild(self)[1:]
def PwChildFirst(self):
return PwBlock.RgpwChild(self)[0]
def DxDyNew(self, w, dxStart, mpksel):
return self.PwChildFirst().DxDyNew(w, dxStart, mpksel)
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
if not fOverlay:
self.PwChildFirst().Draw(ascr, x, y, w, dxStart, mpksel, False)
else:
wMax = self.WidthMax(mpksel)
w = w - dxStart
x = x + dxStart
if x + wMax > w and wMax < w:
x = w - self.WidthMax(mpksel)
PwBlock.Draw(self, ascr, x, y + 1, w, 0, mpksel, False)
class PwList(PwContainer):
def __init__(self, pwParent, scril, dxIndent):
PwContainer.__init__(self, pwParent)
self.scril = scril
self.dxIndent = dxIndent
def Value(self):
return self.scril
def DxDyNew(self, w, dxStart, mpksel):
dx = dxStart
dy = 0
for pw in self.rgpwContents:
(dx, dyPw) = pw.DxDyNew(w, dx, mpksel)
dy = dy + dyPw
return (dx, dy)
def DxIndent(self):
return self.dxIndent
def Draw(self, ascr, x, y, w, dx, mpksel, fOverlay):
for pw in self.rgpwContents:
pw.Draw(ascr, x + self.DxIndent(), y, w - self.DxIndent(), dx, mpksel, fOverlay)
(dx, dy) = pw.DxDyNew(w, dx, mpksel)
y = y + dy
def HandleKey(self, pov, psel, key):
if key == ansi.K_LEFT:
return psel.Dec(self)
elif key == ansi.K_RIGHT:
return psel.Inc(self)
return False
class Ksel(object):
FOTHER = 0x2000
NONE = FOTHER | 0x1000 # OR together all ksel flags and add 0x1000; largest possible ksel
NAV = 0
OTHERNAV = NAV | FOTHER
@staticmethod
def KselBest(ksel1, ksel2):
if ksel1 < ksel2:
return ksel1
return ksel2
class Psel(TPrs):
def InitPersistent(self, pw, ksel):
assert len(pw.RgpwChild()) == 0 #leaf
self.rgo_ipw = self.Rgo_ipwFromPw(pw)
self.ksel = ksel
def Rgo_ipwFromPw(self, pw):
rgo_ipw = []
if pw != None:
while pw.PwParent() != None:
rgo_ipw.insert(0, (pw.Value(), pw.PwParent().RgpwChild().index(pw)))
pw = pw.PwParent()
return rgo_ipw
def Validate(self, pwRoot):
assert pwRoot.PwParent() == None #root
io_ipw = 0
pwSelected = pwRoot
while len(pwSelected.RgpwChild()) > 0 and io_ipw < len(self.rgo_ipw):
(o, ipw) = self.rgo_ipw[io_ipw]
ipwNew = 0
for pwChild in pwSelected.RgpwChild():
if o != None and pwChild.Value() == o:
break
ipwNew = ipwNew + 1
if ipwNew == len(pwSelected.RgpwChild()):
ipwLim = ipw + 1 if ipw < len(pwSelected.RgpwChild()) else len(pwSelected.RgpwChild())
ipwNew = IoDec(pwSelected.RgpwChild(), ipwLim, self.FPwValid)
if ipwNew < 0:
break
pwSelected = pwSelected.RgpwChild()[ipwNew]
io_ipw = io_ipw + 1
# we've made our best guess as to what the closest selectable thing is -- now make sure we point at SOMEthing selectable.
if not pwSelected.FSelectable():
pwT = pwSelected
while pwT != None:
pwSelected = pwT.PwFirstSelectable()
if pwSelected != None:
break
pwT = pwT.PwParent()
self.rgo_ipw = self.Rgo_ipwFromPw(pwSelected)
def FPwValid(self, pw):
if pw.FSelectable():
return True
for pwChild in pw.RgpwChild():
if self.FPwValid(pwChild):
return True
return False
def Value(self, pwRoot):
self.Validate(pwRoot)
if len(self.rgo_ipw) > 0:
return self.rgo_ipw[-1][0]
return None
def PwSelected(self, pwRoot, clevel = None):
self.Validate(pwRoot)
return self.PwSelectedI(pwRoot, self.rgo_ipw[:clevel])
def PwSelectedI(self, pw, rgo_ipw):
for (_, ipw) in rgo_ipw:
pw = pw.RgpwChild()[ipw]
return pw
# contract: pwContainer is actually selected
def Inc(self, pwContainer):
return self.ChangeI(pwContainer, IoInc)
def Dec(self, pwContainer):
return self.ChangeI(pwContainer, IoDec)
def ChangeI(self, pwContainer, fnChange):
clevelChild = 1
pwRoot = pwContainer
while pwRoot.PwParent() != None:
clevelChild = clevelChild + 1
pwRoot = pwRoot.PwParent()
self.Validate(pwRoot)
assert self.PwSelected(pwRoot, clevelChild).PwParent() == pwContainer
ipw = self.rgo_ipw[clevelChild - 1][1]
rgpw = pwContainer.RgpwChild()
ipwNew = fnChange(rgpw, ipw, self.FPwValid)
self.rgo_ipw[clevelChild - 1] = (rgpw[ipwNew].Value(), ipwNew)
self.Validate(pwRoot)
return ipwNew != ipw
# projector overlay -- handles navigation, drawing the projection, etc
class Pov(TokenClient):
def InitPersistent(self, owner, client, block):
TokenClient.InitPersistent(self, owner, client, "drawable", "overlay")
self.block = block
self.pselstate = self.game.rgtoken("pselstate")[0]
def PwProjected(self):
return self.block.Project(None)
def run(self):
while True:
key = self.client.evKey.receive(self)
psel = self.pselstate.PselByClient(self.client)
pwSel = psel.PwSelected(self.PwProjected())
while pwSel != None:
if pwSel.HandleKey(self, psel, key):
break
pwSel = pwSel.PwParent()
def draw(self, ascr, client):
if client == self.client:
pw = self.PwProjected()
mpksel = self.pselstate.GetMpksel(pw, client)
pw.Draw(ascr, 1, 1, ascr.W(), 0, mpksel, False)
pw.Draw(ascr, 1, 1, ascr.W(), 0, mpksel, True)
class PselState(Token):
def InitPersistent(self, owner, block):
Token.InitPersistent(self, owner, "pselstate")
self.block = block
def InitTransient(self):
Token.InitTransient(self)
self.mpclient_psel = {}
def OnLeave(self, client):
del self.mpclient_psel[client]
def OnJoin(self, client):
print "client joined,", client
self.mpclient_psel[client] = Psel(self.block.Project(None).PwFirstSelectable(), Ksel.NAV)
class Mpksel(object):
def __init__(self, pwRoot, client, mpclient_psel):
self.mppw_ksel = {}
for clientT, psel in mpclient_psel.items():
kselNew = Ksel.NAV
if clientT != client:
kselNew = kselNew | Ksel.FOTHER
pw = psel.PwSelected(pwRoot)
self.mppw_ksel[pw] = Ksel.KselBest(kselNew, self.Get(pw))
def Get(self, pw):
return self.mppw_ksel.get(pw, Ksel.NONE)
def GetMpksel(self, pwRoot, client):
return self.Mpksel(pwRoot, client, self.mpclient_psel)
def PselByClient(self, client):
return self.mpclient_psel[client]
def run(self):
print "pselstate running"
with self.game.evLeave.oob(self, self.OnLeave):
while True:
self.OnJoin(self.game.evJoin.receive(self))
class GameScriptTest(Game):
def InitPersistent(self):
Game.InitPersistent(self)
self.block = Block(None)
self.block.InsertScrilAfter(None, ScmdHelloWorld)
self.block.InsertScrilAfter(None, ScmdBlank)
self.block.InsertScrilAfter(None, ScmdHelloWorld)
self.block.InsertScrilAfter(None, ScmdIf)
self.block.InsertScrilAfter(None, ScmdHelloWorld)
def GetRgclsTokTrans(self):
return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]]
class RunnerScriptTest(Runner):
def InitPersistent(self):
self.game = GameScriptTest()
Runner.InitPersistent(self)
def RunGame(self, client):
client.joinGame(self.game)
if __name__ == "__main__":
Run(RunnerScriptTest, "script_test.marm")