From 4e720f0d673aeb2af5f8c48cce3344a01616e00c Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Sun, 5 Jul 2020 17:17:46 -0400 Subject: [PATCH] Refactor / simplify scripting syntax classes * Introduce Stype, a generalized object for producing synts by text matching * consistently use stype to determine what can be inserted in a given place * rewrite SyntDesc to more extensively use Stypes * Introduce SyntHole, a generalized anyblob that can be put anywhere and evals to failure * Remove all data types but flags, introduce bots * Remove math * Remove compiler / VM * Remove unused methods --- engine.py | 7 + script-thoughts.txt | 25 +++ scripting.py | 491 +++++++++++++++++++------------------------- 3 files changed, 241 insertions(+), 282 deletions(-) diff --git a/engine.py b/engine.py index beab6ad..4631c91 100644 --- a/engine.py +++ b/engine.py @@ -28,6 +28,13 @@ from twisted.internet import reactor from tpers import TPrs, TPLS, Version import tpers + +# TPrs - persistent base class; includes migration facilities and the ability to selectively opt-out of +# being persisted. Most long-lived objects should probably be derived from TPrs. +# Ownable - has a parent ownable; die() will be called when its parent dies. +# Taggable - ownable, and also has tags. Assumes an eventual Game ancestor where the tag index is stored. +# Token - taggable, and also has a tasklet that runs for as long as it's alive. + class Event(TPrs): def InitPersistent(self, game): self.game = game diff --git a/script-thoughts.txt b/script-thoughts.txt index dee0bca..efe4eed 100644 --- a/script-thoughts.txt +++ b/script-thoughts.txt @@ -1,3 +1,28 @@ +My old scripting system is an overcomplicated unusable disaster zone!! +Let's start very simply with something like Bitsy. + +* one layer on a board is the Object Layer; it is where the player lives +* there is a static finite set of named objects, no dynamic creation, no querying +* nothing happens without the player bumping into it + +VERBS +* Show Message +* Show Long Message (pop-up) + +* If Then / Else +* Set Flag + +* Set Visibility of to +* Move ... + +EVENTS +* player touches object + +Once this exists we can expand if we want, but in the meantime this would be *awesome*. + +====== +OLD THOUGHTS + script quotas: - infinite loops are bad. - we do not want "new frames" to happen constantly, so a "when this {expr} happens" event will be triggered diff --git a/scripting.py b/scripting.py index c1890bb..bc49924 100644 --- a/scripting.py +++ b/scripting.py @@ -18,95 +18,113 @@ from basetoken import * from tpers import * from util import * from contextlib import contextmanager -from vm import * # sobj -- generic hungarian for any object that is usable in scripts # stmt -- statement; a synt that can be used as a line in a SyntBlock def RegStmt(clsStmt): - SyntLine.rgclsStmt.append(clsStmt) + StypeStmt.rgclsSynt.append(clsStmt) return clsStmt -def RegRtype(clsRtype): - Rtype.rgclsRtype.append(clsRtype) - return clsRtype +class Botdef(TPrs): + def InitPersistent(self, stName, ach, x, y): + self.stName = stName + self.ast = ast + self.x = x + self.y = y + self.syntOnTouch = SyntBlock() -class Rtype(TPrs): - "Runtime type" - rgclsRtype = [] - @classmethod - def RtypeMax(cls): - "Return an instance of this rtype which will match anything that any instance of this rtype matches." - return cls() - def RglitFromSt(self, st): - "Return literal objects that match a (partially entered) string." - return [] - def RgsyntFromSt(self, syntBlock, st): - "Return syntax objects whose rtypes match this that match a (partially entered) string." - for lit in self.RglitFromSt(st): - yield SyntLit(lit, self) - - for synt in self.RgsyntVarRefFromSt(syntBlock, st): - yield synt - - def RgsyntVarRefFromSt(self, syntBlock, st): - "Return variable references that match a (partially entered) string." - while syntBlock != None: - if isinstance(syntBlock, SyntBlock): - for synt in self.RgsyntFromSyntBlock(syntBlock, st): - yield synt - syntBlock = syntBlock.syntParent +class Flagdef(TPrs): + def InitPersistent(self, stName, value = True): + self.stName = stName + self.value = True + +class Rbot(TPrs): + def InitPersistent(self, botdef): + self.botdef = botdef + self.x = botdef.x + self.y = botdef.y + +class Defs(TPrs): + def InitPersistent(self, rgflagdef = None, rgbotdef = None): + self.rgflagdef = rgflagdef or [] + self.rgbotdef = rgbotdef or [] - # helper for RgsyntVarRefFromSt - def RgsyntFromSyntBlock(self, syntBlock, st): - # yield all vars in scope - for syntVar in syntBlock.rgsynt: - if SyntVar.FVarOfType(syntVar, self) and syntVar.name.St().lower().startswith(st.lower()): - yield SyntVarRef(syntVar) + def AddFlag(self, stName, fValue): + self.rgflagdef.append(Flagdef(stName, fValue)) +class Vm(TPrs): + def InitPersistent(self, defs): + self.rgflagdef = defs.rgflagdef + self.rgbotdef = defs.rgbotdef + self.mpflagdef = { flagdef: flagdef.value for flagdef in defs.rgflagdef } + self.mpbotdef = { botdef: Rbot(botdef) for botdef in defs.rgbotdef } + def SetFlag(self, flagdef, fValue): + self.mpflagdef[flagdef] = fValue + def FFlagSet(self, flagdef): + return self.mpflagdef[flagdef] + + def Log(self, fail): + print(fail.stMessage, fail.synt) + +class Stype(TPrs): + "Syntax type" + def RgsyntFromSt(self, defs, st): + "Return syntax objects whose rtypes match this that match a (partially entered) string." + return [] + +class StypeEnum(Stype): + @classmethod + def RgclsSynt(cls): + return cls.rgclsSynt + def RgsyntFromSt(self, defs, st): + for clsStmt in self.rgclsSynt: + if clsStmt.StForTypein().lower().startswith(st.lower()): + yield clsStmt() + +class StypeStmt(StypeEnum): + rgclsSynt = [] + +class Rtype(Stype): + "Runtime type" def StForSobj(self, sobj): "Return a user-visible description of a sobj." return str(sobj) + def FMember(self, sobj): "Returns true if sobj is a member of this type." return isinstance(sobj, self.pythontype) - def FOverlap(self, rtype): - "Returns true if there is some overlap between this type and rtype." - return isinstance(rtype, self.__class__) -@RegRtype class RtypeBool(Rtype): pythontype = bool - def RglitFromSt(self, st): + def RgsyntFromSt(self, defs, st): if "true".startswith(st.lower()): - yield True + yield SyntLit(True, self) if "false".startswith(st.lower()): - yield False -@RegRtype -class RtypeNum(Rtype): - pythontype = float - def RglitFromSt(self, st): - try: - yield float(st) - except: - pass -@RegRtype -class RtypeString(Rtype): - pythontype = str - def RglitFromSt(self, st): - if st.startswith('"') or st.startswith("'"): - yield st[1:] + yield SyntLit(False, self) -class RtypeAny(Rtype): - def RgsyntFromSt(self, syntBlock, st): - for clsRtype in self.rgclsRtype: - rtype = clsRtype.RtypeMax() - for synt in rtype.RgsyntFromSt(syntBlock, st): +class RtypeFlag(Rtype): + pythontype = Flagdef + def RgsyntFromSt(self, defs, st): + return (SyntFlagRef(flagdef) for flagdef in defs.rgflagdef if flagdef.stName.lower().startswith(st.lower())) + +class RtypeUnion(Rtype): + def InitPersistent(self, *rgrtype): + self.rgrtype = rgrtype + + def RgsyntFromSt(self, defs, st): + for rtype in self.rgrtype: + for synt in rtype.RgsyntFromSt(defs, st): yield synt + + def StForSobj(self, sobj): + for rtype in self.rgrtype: + if rtype.FMember(sobj): + return rtype.StForSobj(sobj) + return str(sobj) + def FMember(self, sobj): - return True - def FOverlap(self, rtype): - return True - + return any((rtype.FMember(sobj) for rtype in self.rgrtype)) + class Typeable(TPrs): def InitTransient(self): self.steditTypein = Stedit() @@ -129,11 +147,10 @@ class Synt(Typeable): def SyntDefault(cls): return cls() - @classmethod - def RgsyntReplace(cls, syntChild, st, rtype): - return [] + def ProjectTypein(self, pcur): + return self.syntParent.ProjectTypeinForChild(pcur.defs, pcur.PwHoriz(self), self, self.StForTypein()) - def ProjectTypeinForChild(self, pwParent, syntChild, st): + def ProjectTypeinForChild(self, defs, pwParent, syntChild, st): def OnSelect(synt, psel): self.Replace(syntChild, synt) syntChild.SetStTypein(None) @@ -141,11 +158,13 @@ class Synt(Typeable): pwParent = PwDropdown(pwParent) PwTypein(pwParent, st, syntChild) if syntChild.GetStTypein() != None: - for synt in self.RgsyntForChild(syntChild, syntChild.GetStTypein()): - PwButton(pwParent, synt.StForTypein(), synt, OnSelect) + stype = self.StypeForChild(syntChild) + if stype: + for synt in stype.RgsyntFromSt(defs, syntChild.GetStTypein()): + PwButton(pwParent, synt.StForTypein(), synt, OnSelect) - def RgsyntForChild(self, syntChild, st): - return [] + def StypeForChild(self, syntChild): + return None def Replace(self, syntOld, syntNew): assert syntNew.syntParent == None @@ -162,12 +181,6 @@ class Synt(Typeable): return syntChild return self.rgsynt.index(syntChild) - def Rtype(self): - return None - - def RtypeTopForChild(self, syntChild): - return None - def Populate(self): "Populate rgsynt with useful default values." pass @@ -175,20 +188,17 @@ class Synt(Typeable): def Project(self, pcur): "Project the current synt into its corresponding pws." pass - def Compile(self): - "Return a list of instrs to be interpreted. See vm.py for details on what an instr can be." - return [self.Eval] + def Eval(self, vm): + "Execute yourself, in the context of vm." + return Fail("Missing information", self) - # desc - list of desces # desce: # string: "foo" -- literal uneditable text # list: ["foo"] -- text to edit the current synt -# tuple: (clsSynt, type) -- child description -# clsSynt: class of child synt -# type: number - same as another child expression with that number -# None - no rtype specified / possible -# tuple (number, rtypeTop) - number == same as another child expression with that number, rtypeTop = required type +# synt: synt - insert an empty instance of this synt +# stype: stype - insert a SyntHole, use stype to determine what can go there +# tuple: (stype, synt) - insert a Synt that can replace itself, use stype to determine what can go there class SyntDesc(Synt): @classmethod def StForTypein(cls): @@ -210,37 +220,30 @@ class SyntDesc(Synt): return cls.desc def Populate(self): for desce in self.Desc(): - if isinstance(desce, tuple): - synt = desce[0].SyntDefault() - self.Append(synt) -# for synt in self.rgsynt: -# synt.Populate() + if hasattr(desce, "SyntDefault"): + self.Append(desce.SyntDefault()) + elif isinstance(desce, tuple): + self.Append(desce[1].SyntDefault()) + elif isinstance(desce, Stype): + self.Append(SyntHole.SyntDefault()) def DesceChild(self, isyntChild): - isyntDesce = 0; + isyntDesce = 0 for desce in self.Desc(): - if isinstance(desce, tuple): + if isinstance(desce, Stype) or hasattr(desce, "SyntDefault") or isinstance(desce, tuple): if isyntDesce == isyntChild: return desce isyntDesce += 1 - return None - - def RtypeTopForChild(self, syntChild): - isyntChild = self.Isynt(syntChild) - desce = self.DesceChild(isyntChild) - if desce != None and isinstance(desce[1], tuple): - return desce[1][0] return None - def RgsyntForChild(self, syntChild, st): + def StypeForChild(self, syntChild): isyntChild = self.Isynt(syntChild) desce = self.DesceChild(isyntChild) - if desce != None: - rtype = None - if isinstance(desce[1], tuple): - rtype = desce[1][1] - return desce[0].RgsyntReplace(syntChild, st, rtype) - return [] + if isinstance(desce, Stype): + return desce + elif isinstance(desce, tuple): + return desce[0] + def Project(self, pcur): "adds more horizontal pws to a horizontal pw" isynt = 0 @@ -249,13 +252,13 @@ class SyntDesc(Synt): PwStatic(pcur.PwHoriz(self), desce) elif isinstance(desce, list): # selection for the synt itself - self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, desce[0]) - elif isinstance(desce, tuple): + self.ProjectTypein(pcur) + elif isinstance(desce, Stype) or hasattr(desce, "SyntDefault") or isinstance(desce, tuple): # embedded syntax self.rgsynt[isynt].Project(pcur) isynt += 1 - -class SyntName(Synt): + +class SyntText(Synt): def InitPersistent(self): Synt.InitPersistent(self) self.st = "" @@ -263,39 +266,18 @@ class SyntName(Synt): Synt.InitTransient(self) self.SetStTypein(self.st) def Project(self, pcur): - PwTypein(pcur.PwHoriz(self), self.St(), self) + PwTypein(pcur.PwHoriz(self), self.St(), self, ansi.GREEN) def St(self): return self.GetStTypein() def HandleTypeinKey(self, key): val = Synt.HandleTypeinKey(self, key) self.st = self.GetStTypein() return val - -class SyntExpr(Synt): - rgclsSyntOp = [] - @classmethod - def RgsyntReplace(cls, syntChild, st, rtype): - for synt in RtypeAny().RgsyntFromSt(syntChild.syntParent, st): - yield synt - for clsSyntOp in cls.rgclsSyntOp: - if clsSyntOp.StForTypein().lower().startswith(st.lower()): - yield clsSyntOp.SyntDefault() - - def Project(self, pcur): - self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, " ") def Eval(self, vm): - Fail.Push(vm, "Empty expression", self) + return self.st -class SyntLine(SyntDesc): - rgclsStmt = [] - desc = [[" "]] - @classmethod - def RgsyntReplace(cls, syntChild, st, rtype): - for clsStmt in cls.rgclsStmt: - if clsStmt.StForTypein().lower().startswith(st.lower()): - yield clsStmt() - def Compile(self): - return [] +class SyntHole(SyntDesc): + desc = [[" "]] class SyntBlock(Synt): def Project(self, pcur): @@ -305,19 +287,19 @@ class SyntBlock(Synt): pcur.pwVert = PwBlock(None, self, pcur.dxindent) def OnInsertNewLine(syntAfter, psel): self.InsertLineAfter(syntAfter, None) - psel.Inc(pcur.pwVert) + psel.Inc(pcur.pwVert) # does nothing because we need to reproject PwButtonHidden(pcur.pwVert, "[insert new line]", None, OnInsertNewLine, pcur.dxindent) for syntLine in self.rgsynt: pwKey = PwKeyHandler(pcur.pwVert, self.HandleKey) with pcur.ProjectHoriz(pwKey, syntLine): syntLine.Project(pcur) - - def RgsyntForChild(self, syntChild, st): - return SyntLine.RgsyntReplace(syntChild, st, None) + def StypeForChild(self, syntChild): + return StypeStmt() + def InsertLineAfter(self, syntAfter, syntStmt): if syntStmt == None: - syntStmt = SyntLine() + syntStmt = SyntHole() if syntAfter == None: self.rgsynt.insert(0, syntStmt) else: @@ -331,8 +313,11 @@ class SyntBlock(Synt): psel.Inc(pwKey.PwParent()) return True return False - def Compile(self): - return self.rgsynt + + def Eval(self, vm): + for synt in self.rgsynt: + # todo: log failures + synt.Eval(vm) class SyntLit(Synt): def InitPersistent(self, value, rtype): @@ -344,137 +329,80 @@ class SyntLit(Synt): def Rtype(self): return self.rtype def Project(self, pcur): - self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein()) + self.ProjectTypein(pcur) def Eval(self, vm): - vm.Push(self.value) + return self.value + +class SyntFlagRef(Synt): + def InitPersistent(self, flagdef = None): + Synt.InitPersistent(self) + self.flagdef = flagdef + + def StForTypein(self): + if self.flagdef: + return self.flagdef.stName + return "" + + def Project(self, pcur): + self.ProjectTypein(pcur) + + def Eval(self, vm): + try: + return vm.FFlagSet(self.flagdef) + except: + return Fail("No such flag", self) + +class SyntIsFlagSet(SyntDesc): + desc = [["set"]] + def Eval(self, vm, val): + return val +class SyntIsFlagUnset(SyntDesc): + desc = [["not set"]] + def Eval(self, vm, val): + return not val +class SyntIsFlagEqualTo(SyntDesc): + desc = [["equal to"], " ", RtypeFlag()] + flag = SyntDesc.DefProp(0) + def Eval(self, vm, val): + return val == self.flag.Eval(vm) +class SyntIsFlagNotEqualTo(SyntDesc): + desc = [["not equal to"], " ", RtypeFlag()] + flag = SyntDesc.DefProp(0) + def Eval(self, vm, val): + return val != self.flag.Eval(vm) + +class StypeFlagTest(StypeEnum): + rgclsSynt = [SyntIsFlagSet, SyntIsFlagUnset, SyntIsFlagEqualTo, SyntIsFlagNotEqualTo] @RegStmt -class SyntVar(SyntDesc): - desc = [["Define"], " ", (SyntName, None), " to be ", (SyntExpr, 1)] - name = SyntDesc.DefProp(0) - expr = SyntDesc.DefProp(1) - @classmethod - def FVarOfType(cls, synt, rtype): - return isinstance(synt, cls) and synt.expr != None and rtype.FOverlap(synt.expr.Rtype()) - def Compile(self): - return [self.expr, self.Eval] - def Eval(self, vm): - vm.vars.Define(self, vm.Pop()) - -class SyntVarRef(Synt): - def InitPersistent(self, syntVar = None): - Synt.InitPersistent(self) - self.syntVar = syntVar - @classmethod - def RgsyntReplace(cls, syntChild, st, rtype): - rtype = rtype or RtypeAny() - return rtype.RgsyntVarRefFromSt(syntChild, st) - def Rtype(self): - return self.syntVar.Rtype() - def StForTypein(self): - if self.syntVar: - return self.syntVar.name.St() - return "" - def Project(self, pcur): - self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein()) - def Eval(self, vm): - vm.Push(vm.vars.Get(self.syntVar, self)) - -class SyntBinOp(SyntDesc): - @classmethod - def Desc(cls): - return [(SyntExpr, None), " ", [cls.op], " ", (SyntExpr, None)] - left = SyntDesc.DefProp(0) - right = SyntDesc.DefProp(1) - @classmethod - def Create(cls, op, rtype, dgEval = None, stNameI = None): - def Decorate(dgEval): - stName = stNameI or dgEval.__name__ - def Eval(self, vm): - right = vm.Pop() - left = vm.Pop() - try: - vm.Push(dgEval(left, right)) - except Exception as e: - Fail.Push(vm, "Failed to " + op + ": " + str(e), self) - def Compile(self): - return [self.left, self.right, self.Eval] - clsNew = type(stName, (cls,), {"Compile": Compile, "Eval": Eval, "op": op}) - SyntExpr.rgclsSyntOp.append(clsNew) - return clsNew - - if dgEval == None: # used as a decorator - return Decorate - clsNew = Decorate(dgEval) - if stNameI != None: - globals()[stNameI] = clsNew - return clsNew - -SyntBinOp.Create("+", RtypeNum(), lambda l,r: l + r, "SyntPlus") -SyntBinOp.Create("-", RtypeNum(), lambda l,r: l - r, "SyntMinus") -SyntBinOp.Create("*", RtypeNum(), lambda l,r: l * r, "SyntMult") -SyntBinOp.Create("/", RtypeNum(), lambda l,r: l / r, "SyntDiv") # use ansi? -SyntBinOp.Create("=", RtypeBool(), lambda l,r: l == r, "SyntEq") -SyntBinOp.Create(">", RtypeBool(), lambda l,r: l > r, "SyntGt") -SyntBinOp.Create(">=", RtypeBool(), lambda l,r: l >= r, "SyntGte") # use ansi? -SyntBinOp.Create("<", RtypeBool(), lambda l,r: l < r, "SyntLt") -SyntBinOp.Create("<=", RtypeBool(), lambda l,r: l <= r, "SyntLte") # use ansi? -SyntBinOp.Create("and", RtypeBool(), lambda l,r: l and r, "SyntAnd") -SyntBinOp.Create("or", RtypeBool(), lambda l,r: l or r, "SyntOr") - -@RegStmt class SyntIf(SyntDesc): - desc = [["If"], " ", (SyntExpr, (1, RtypeBool)), ", then:", (SyntBlock, None), "or else:", (SyntBlock, None)] + desc = [["If"], " ", RtypeFlag(), " is ", (StypeFlagTest(), SyntIsFlagSet), ", then:", SyntBlock, "or else:", SyntBlock] expr = SyntDesc.DefProp(0) - blockIfTrue = SyntDesc.DefProp(1) - blockIfFalse = SyntDesc.DefProp(2) - def Compile(self): - return [self.expr, self.Compare, self.PopCtx] - def Compare(self, vm): - val = vm.Pop() - vm.vars.Push() # lexical scoping, bitches - if val: - return self.blockIfTrue + test = SyntDesc.DefProp(1) + blockIfTrue = SyntDesc.DefProp(2) + blockIfFalse = SyntDesc.DefProp(3) + def Eval(self, vm): + if self.test.Eval(vm, self.expr.Eval(vm)): + return self.blockIfTrue.Eval(vm) else: - return self.blockIfFalse - def PopCtx(self, vm): - vm.vars.Pop() + return self.blockIfFalse.Eval(vm) @RegStmt class SyntSet(SyntDesc): - desc = [["Set"], " ", (SyntVarRef, 1), " to ", (SyntExpr, 1)] + desc = [["Set flag"], " ", RtypeFlag(), " to ", RtypeUnion(RtypeBool(), RtypeFlag())] lvalue = SyntDesc.DefProp(0) expr = SyntDesc.DefProp(1) - def Compile(self): - return [self.expr, self.Eval] def Eval(self, vm): - val = vm.Pop() - if not isinstance(val, Fail): - vm.Log(vm.vars.Set(self.lvalue.syntVar, vm.Pop(), self)) + # todo: fail if flagdef or expr isn't set properly? + vm.SetFlag(self.lvalue.flagdef, self.expr.Eval(vm)) -class SyntEvent(SyntDesc): - rgclsSyntEvent = [] - desc = [[" "]] - @classmethod - def RgsyntReplace(cls, syntChild, st, rtype): - for clsSyntEvent in cls.rgclsSyntEvent: - if clsSyntEvent.StForTypein().lower().startswith(st.lower()): - yield clsSyntEvent.SyntDefault() - for synt in SyntExpr.RgsyntReplace(syntChild, st, rtype): - yield synt - -class SyntWhen(SyntDesc): - desc = [["When"], " ", (SyntEvent, 1), ":", (SyntBlock, 2)] - -#debug @RegStmt class SyntPrint(SyntDesc): - desc = [["Print"], " ", (SyntExpr, 1)] + desc = [["Show Message"], " \"", SyntText, "\""] expr = SyntDesc.DefProp(0) - def Compile(self): - return [self.expr, self.Eval] def Eval(self, vm): - print vm.Pop() + # todo + print(self.expr.Eval(vm)) class Fail(TPrs): """ @@ -483,27 +411,21 @@ 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, stFailure, synt): + def InitPersistent(self, vm, stFailure, synt): self.stFailure = stFailure self.synt = synt - @staticmethod - def Push(vm, stFailure, synt): - fail = Fail(stFailure, synt) - vm.Push(fail) - vm.Log(fail) - @staticmethod - def Log(vm, stFailure, synt): - vm.Log(Fail(stFailure, synt)) + vm.Log(self) # projection cursor class Pcur(object): @staticmethod - def PwProjected(synt): - pcur = Pcur() + def PwProjected(defs, synt): + pcur = Pcur(defs) synt.Project(pcur) return pcur.pwVert - def __init__(self): + def __init__(self, defs): + self.defs = defs self.pwVert = None self.pwHoriz = None self.dxindent = 0 @@ -633,13 +555,14 @@ class PwStatic(Pw): ascr.PutSt(snippet.st, x, y, self.ColFg(), self.ColBg(ksel)) class PwTypein(PwStatic): - def __init__(self, pwParent, stSobj, typeable): + def __init__(self, pwParent, stSobj, typeable, colBgDefault = ansi.BLUE): if typeable.GetStTypein() == None: stDisplay = stSobj else: stDisplay = None PwStatic.__init__(self, pwParent, stDisplay) self.typeable = typeable + self.colBgDefault = colBgDefault def Value(self): return self.typeable def StTextDisplay(self, ksel): @@ -653,7 +576,7 @@ class PwTypein(PwStatic): return ansi.YELLOW elif ksel == Ksel.OTHERNAV: return ansi.MAGENTA - return ansi.BLUE + return self.colBgDefault def HandleKey(self, pov, psel, key): return self.typeable.HandleTypeinKey(key) def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay): @@ -899,20 +822,20 @@ class Psel(TPrs): # projector overlay -- handles navigation, drawing the projection, etc class Pov(TokenClient): - def InitPersistent(self, owner, client, block): + def InitPersistent(self, owner, client, defs, block): TokenClient.InitPersistent(self, owner, client, "drawable", "overlay") + self.defs = defs self.block = block self.pselstate = self.game.rgtoken("pselstate")[0] def PwProjected(self): - return Pcur.PwProjected(self.block) + return Pcur.PwProjected(self.defs, self.block) def run(self): while True: key = self.client.evKey.receive(self) if key == ansi.K_PGDN: - Vm().RunSynt(self.block) - continue + self.block.Eval(Vm(self.defs)) psel = self.pselstate.PselByClient(self.client) pwSel = psel.PwSelected(self.PwProjected()) while pwSel != None: @@ -928,8 +851,9 @@ class Pov(TokenClient): pw.Draw(ascr, 1, 1, ascr.W(), 0, mpksel, True) class PselState(LeaveJoinToken): - def InitPersistent(self, owner, block): + def InitPersistent(self, owner, defs, block): Token.InitPersistent(self, owner, "pselstate") + self.defs = defs self.block = block def InitTransient(self): Token.InitTransient(self) @@ -937,8 +861,8 @@ class PselState(LeaveJoinToken): def OnLeave(self, client): del self.mpclient_psel[client] def OnJoin(self, client): - print "client joined,", client - self.mpclient_psel[client] = Psel(Pcur.PwProjected(self.block).PwFirstSelectable(), Ksel.NAV) + print("client joined,", client) + self.mpclient_psel[client] = Psel(Pcur.PwProjected(self.defs, self.block).PwFirstSelectable(), Ksel.NAV) class Mpksel(object): def __init__(self, pwRoot, client, mpclient_psel): self.mppw_ksel = {} @@ -960,10 +884,13 @@ class PselState(LeaveJoinToken): class GameScriptTest(Game): def InitPersistent(self): Game.InitPersistent(self) + self.defs = Defs() + self.defs.AddFlag("flag1", True) + self.defs.AddFlag("flag2", False) self.block = SyntBlock() def GetRgclsTokTrans(self): - return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]] + return [[PselState, self.defs, self.block], [AutoJoiner, [Pov, self.defs, self.block]]] class RunnerScriptTest(Runner): def InitPersistent(self):