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
This commit is contained in:
Jeremy Penner 2020-07-05 17:17:46 -04:00
parent 6790f23474
commit 4e720f0d67
3 changed files with 241 additions and 282 deletions

View file

@ -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

View file

@ -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 <string>
* Show Long Message (pop-up) <textarea?>
* If <flag> Then / Else
* Set Flag <true/false/flag>
* Set Visibility of <object | layer> to <true/false/flag>
* Move <object> <N/E/W/S>...
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

View file

@ -18,94 +18,112 @@ 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):
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 []
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."
for lit in self.RglitFromSt(st):
yield SyntLit(lit, self)
return []
for synt in self.RgsyntVarRefFromSt(syntBlock, st):
yield synt
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()
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
# 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)
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):
@ -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):
def StypeForChild(self, syntChild):
isyntChild = self.Isynt(syntChild)
desce = self.DesceChild(isyntChild)
if desce != None and isinstance(desce[1], tuple):
return desce[1][0]
return None
if isinstance(desce, Stype):
return desce
elif isinstance(desce, tuple):
return desce[0]
def RgsyntForChild(self, syntChild, st):
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 []
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
@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):
class SyntFlagRef(Synt):
def InitPersistent(self, flagdef = 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()
self.flagdef = flagdef
def StForTypein(self):
if self.syntVar:
return self.syntVar.name.St()
return "<var>"
if self.flagdef:
return self.flagdef.stName
return "<flag>"
def Project(self, pcur):
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein())
self.ProjectTypein(pcur)
def Eval(self, vm):
vm.Push(vm.vars.Get(self.syntVar, self))
try:
return vm.FFlagSet(self.flagdef)
except:
return Fail("No such flag", 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
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)
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")
class StypeFlagTest(StypeEnum):
rgclsSynt = [SyntIsFlagSet, SyntIsFlagUnset, SyntIsFlagEqualTo, SyntIsFlagNotEqualTo]
@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):