initial commit

This commit is contained in:
Jeremy Penner 2011-03-18 17:10:02 -07:00
commit 5d61e939aa
24 changed files with 4557 additions and 0 deletions

2
Makefile Normal file
View file

@ -0,0 +1,2 @@
all:
python setup.py build_ext --inplace

13
ansi.py Normal file
View file

@ -0,0 +1,13 @@
#@+leo-ver=4-thin
#@+node:jpenner.20091215224421.2:@thin ansi.py
import config
if config.USE_CYTHON:
from ansi_cython import *
else:
from ansi_python import *
#@+others
#@-others
#@nonl
#@-node:jpenner.20091215224421.2:@thin ansi.py
#@-leo

540
ansi_cython.pyx Normal file
View file

@ -0,0 +1,540 @@
#@+leo-ver=4-thin
#@+node:jpenner.20091212133112.2:@thin ansi_cython.pyx
#@@language python
import config
cdef extern from "stdio.h":
int sprintf(char *, char *,...)
cdef extern from "stdlib.h":
ctypedef unsigned long size_t
void free(void *ptr)
void *malloc(size_t size)
void *calloc(size_t nelem, size_t elsize)
void *realloc(void *ptr, size_t size)
size_t strlen(char *s)
char *strcpy(char *dest, char *src)
#@+others
#@+node:jpenner.20091212133112.3:Codes
esc = '%s['%chr(27)
reset = '%s0m'%esc
cls = '%s2j'%esc
BLACK = 0
RED = 1
GREEN = 2
YELLOW = 3
BLUE = 4
MAGENTA = 5
CYAN = 6
WHITE = 7
FBRIGHT = 8
FBLINK = 16
rgcolorBg = range(8)
rgcolorFg = range(8)
rgcolorFg.extend([col | FBRIGHT for col in range(8)])
K_BACKSPACE = chr(8)
K_TAB = chr(9)
K_RETURN = chr(10)
K_DEL = chr(127)
K_LEFT = 256
K_RIGHT = 257
K_UP = 258
K_DOWN = 259
K_HOME = 260
K_END = 261
K_PGUP = 262
K_PGDN = 263
def StrKey(ch):
if type(ch) == str:
return ord(ch)
return str(ch)
def Ctrl(ch):
ch = ch.upper()
assert ch != 'M' and ch != 'J' and ch != 'H'
return chr(ord(ch - 'A' + 1))
def FEnter(key):
return key == "\n" or key == "\r"
#@nonl
#@-node:jpenner.20091212133112.3:Codes
#@+node:jpenner.20091212133112.4:Ach
# ANSI Character - contains prop and character
cdef struct SAch:
unsigned char ch
char fgCol
char bgCol
cdef union UAch:
int ach
SAch sach
cpdef MkAch(char *ch, char fgcol=WHITE, char bgcol=BLACK):
cdef UAch uach
uach.sach.ch = ch[0]
uach.sach.fgCol = fgcol
uach.sach.bgCol = bgcol
return uach.ach
# the class must be named Ach for backwards compatibility, but the hungarian name is OAch
class Ach(object):
def __init__(self, int ach):
cdef UAch uach
uach.ach = ach
self.ch = chr(uach.sach.ch)
self.fgCol = uach.sach.fgCol
self.bgCol = uach.sach.bgCol
def ToAch(self):
return MkAch(self.ch, self.fgCol, self.bgCol)
cdef AchFromOach(oach):
if oach == None:
return achBlankI
return MkAch(oach.ch, oach.fgCol, oach.bgCol)
cdef OachFromAch(int ach):
if ach == achBlankI:
return None
assert ach != achInvdI
return Ach(ach)
def ChFromAch(int ach):
cdef UAch uach
uach.ach = ach
return chr(uach.sach.ch)
achBlank = 0
achInvd = -1
cdef enum:
achBlankI = 0
achInvdI = -1
chesc = 27
FBRIGHTI = 8
FBLINKI = 16
cdef inline AstFromAch(int ach, int achPrev = achInvdI):
cdef UAch uach, uachPrev
uach.ach = ach
uachPrev.ach = achPrev
cdef char ast[60]
cdef char sgr[4]
cdef int csgr = 0
if (achPrev == achInvdI) or (uachPrev.sach.fgCol != uach.sach.fgCol):
sgr[csgr] = (uach.sach.fgCol & 7) + 30
csgr = csgr + 1
fBright = uach.sach.fgCol & FBRIGHTI
if (achPrev == achInvdI) or (fBright != uachPrev.sach.fgCol & FBRIGHTI):
if fBright:
sgr[csgr] = 1
else:
sgr[csgr] = 2
csgr = csgr + 1
fBlink = uach.sach.fgCol & FBLINKI
if (achPrev == achInvdI) or (fBlink != uachPrev.sach.fgCol & FBLINKI):
if fBlink:
sgr[csgr] = 5
else:
sgr[csgr] = 25
csgr = csgr + 1
if (achPrev == achInvdI) or (uachPrev.sach.bgCol != uach.sach.bgCol):
sgr[csgr] = uach.sach.bgCol + 40
csgr = csgr + 1
if csgr == 0:
sprintf(ast, "%c", uach.sach.ch)
elif csgr == 1:
sprintf(ast, "%c[%dm%c", chesc, sgr[0], uach.sach.ch)
elif csgr == 2:
sprintf(ast, "%c[%d;%dm%c", chesc, sgr[0], sgr[1], uach.sach.ch)
elif csgr == 3:
sprintf(ast, "%c[%d;%d;%dm%c", chesc, sgr[0], sgr[1], sgr[2], uach.sach.ch)
elif csgr == 4:
sprintf(ast, "%c[%d;%d;%d;%dm%c", chesc, sgr[0], sgr[1], sgr[2], sgr[3], uach.sach.ch)
else:
assert csgr >= 0 and csgr <= 4, "more sgr possibilities, please handle"
return ast
#@-node:jpenner.20091212133112.4:Ach
#@+node:jpenner.20091212133112.5:HTML
mpch_entity = [0, 9786, 9787, 9829, 9830, 9827, 9824, 8226, 9688, 9675, 9689, 9794, 9792, 9834, 9835, 9788, 9658, 9668, 8597, 8252,
182, 167, 9644, 8616, 8593, 8595, 8594, 8592, 8735, 8596, 9650, 9660, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
8962, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251,
249, 255, 214, 220, 162, 163, 165, 8359, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171,
187, 9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516,
9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554, 9555,
9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734,
966, 949, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160]
setch_unsafe = set([ord('&'), ord('<'), ord('>'), ord('"'), ord("'")])
mpcol_hcol = ["#000000", "#AA0000", "#00AA00", "#AA5500", "#0000AA", "#AA00AA", "#00AAAA", "#AAAAAA",
"#555555", "#FF5555", "#55FF55", "#FFFF55", "#5555FF", "#FF55FF", "#55FFFF", "#FFFFFF"]
cdef HstFromAch(int ach, int achPrev = achInvdI):
cdef UAch uach, uachPrev
uach.ach = ach
uachPrev.ach = achPrev
stStyle = None
if achPrev == achInvdI or uachPrev.sach.fgCol != uach.sach.fgCol or uachPrev.sach.bgCol != uach.sach.bgCol:
stStyle = "color:" + mpcol_hcol[uach.sach.fgCol & 15] + ";background-color:" + mpcol_hcol[uach.sach.bgCol & 15]
rgst = []
if stStyle != None and achPrev != achInvdI:
rgst.append("</span>")
if stStyle != None:
rgst.append("<span style='" + stStyle + "'>")
if ach == achBlank:
rgst.append(' ')
else:
entity = mpch_entity[uach.sach.ch]
if entity == uach.sach.ch and not uach.sach.ch in setch_unsafe:
rgst.append(chr(uach.sach.ch))
else:
rgst.append("&#" + str(entity) + ";")
return ''.join(rgst)
#@-node:jpenner.20091212133112.5:HTML
#@+node:jpenner.20091212133112.6:Pos
class Pos(object):
def __init__(self, int w=config.W, int h=config.H, int x=1, int y=1):
self.i = PosI(w, h, x, y)
def X(self):
cdef PosI posI = self.i
return posI.X()
def Y(self):
cdef PosI posI = self.i
return posI.Y()
def Inc(self):
cdef PosI posI = self.i
posI.Inc()
def Up(self):
cdef PosI posI = self.i
return posI.Up()
def Down(self):
cdef PosI posI = self.i
return posI.Down()
def Left(self):
cdef PosI posI = self.i
return posI.Left()
def Right(self):
cdef PosI posI = self.i
return posI.Right()
def __setstate__(self, state):
self.i = PosI(state["w"], state["h"], state["xz"] + 1, state["yz"] + 1)
def __getstate__(self):
cdef PosI posI = self.i
return {"w": posI.w, "h": posI.h, "xz": posI.xz, "yz": posI.yz}
cdef class PosI(object):
cdef int w, h, xz, yz
def __init__(self, int w=config.W, int h=config.H, int x=1, int y=1):
self.w = w
self.h = h
self.xz = x - 1
self.yz = y - 1
cdef inline X(self): return self.xz + 1
cdef inline Y(self): return self.yz + 1
cdef inline Inc(self):
if self.xz == self.w - 1:
if self.yz < self.h:
self.xz = 0
self.yz = self.yz + 1
else:
self.xz = self.xz + 1
cdef inline Up(self):
if self.yz > 0:
self.yz = self.yz - 1
return True
cdef inline Down(self):
if self.yz < self.h - 1:
self.yz = self.yz + 1
return True
cdef inline Left(self):
if self.xz > 0:
self.xz = self.xz - 1
return True
cdef inline Right(self):
if self.xz < self.w - 1:
self.xz = self.xz + 1
return True
cdef ToPos(self):
return Pos(self.w, self.h, self.X(), self.Y())
#@nonl
#@-node:jpenner.20091212133112.6:Pos
#@+node:jpenner.20100105170222.1:Ascr
class Ascr(object):
def __init__(self, int w=config.W, int h=config.H, int achFill = achBlankI):
cdef AscrI ascrI = AscrI(w,h)
self.i = ascrI
if achFill != achBlankI:
ascrI.Fill(achFill, w, h)
def __setstate__(self, state):
cdef AscrI ascrI = AscrI(state["w"], state["h"])
self.i = ascrI
cdef int iach = 0
for mpxz_oach in state["mpyzxz_ach"]:
for oach in mpxz_oach:
ascrI.rgach[iach] = AchFromOach(oach)
iach = iach + 1
def __getstate__(self):
cdef AscrI ascrI = self.i
cdef int iach = 0
mpyzxz_oach = []
for yz in range(ascrI.h):
mpxz_oach = []
for xz in range(ascrI.w):
mpxz_oach.append(OachFromAch(ascrI.rgach[iach]))
iach = iach + 1
mpyzxz_oach.append(mpxz_oach)
return {"w":ascrI.w, "h":ascrI.h, "mpyzxz_ach": mpyzxz_oach}
def W(self):
cdef AscrI ascrI = self.i
return ascrI.w
def H(self):
cdef AscrI ascrI = self.i
return ascrI.h
def ZPos(self, int xz, int yz):
cdef AscrI ascrI = self.i
return ascrI.ZPos(xz, yz)
#@ @+others
#@+node:jpenner.20100105170222.2:Put
def PutAch(self, int ach, int x, int y):
cdef AscrI ascrI = self.i
ascrI.PutAch(ach, x, y)
def GetAch(self, int x, int y):
cdef AscrI ascrI = self.i
return ascrI.rgach[ascrI.IAch(x - 1, y - 1)]
def PutRgach(self, rgach, int x, int y):
cdef AscrI ascrI = self.i
ascrI.PutRgach(rgach, x, y)
def PutSt(self, char *st, int x, int y, int colFg = WHITE, int colBg=BLACK):
cdef AscrI ascrI = self.i
ascrI.PutSt(st, x, y, colFg, colBg)
def Fill(self, int ach, int wIn, int hIn, int x = 1, int y = 1):
cdef AscrI ascrI = self.i
ascrI.Fill(ach, wIn, hIn, x, y)
def PutAscr(self, ascr, int x=1, int y=1):
cdef AscrI ascrI = self.i
ascrI.PutAscr(ascr.i, x, y)
#@nonl
#@-node:jpenner.20100105170222.2:Put
#@+node:jpenner.20100105170222.3:Diff
def AstDiff(self, ascr):
cdef AscrI ascrI = self.i
return ascrI.AstDiff(ascr.i)
def Hst(self):
cdef AscrI ascrI = self.i
return ascrI.Hst()
#@-node:jpenner.20100105170222.3:Diff
#@+node:jpenner.20091212133112.10:Ast
def Ast(self):
return Ascr(self.W(), self.H(), achInvdI).AstDiff(self) #stupid implementation
#@nonl
#@-node:jpenner.20091212133112.10:Ast
#@-others
#@-node:jpenner.20100105170222.1:Ascr
#@+node:jpenner.20091212133112.7:AscrI
# ANSI Screen
cdef class AscrI(object):
cdef int w, h
cdef int *rgach
def __cinit__(self, int w=config.W, int h=config.H, int achFill = achBlankI):
self.rgach = <int*>calloc(w * h, sizeof(int))
if achFill != achBlankI:
for iach in range(w * h):
self.rgach[iach] = achFill
self.w = w
self.h = h
def __dealloc__(self):
free(self.rgach)
cdef Zpos(self, int xz, int yz):
return Pos(self.w, self.h, xz + 1, yz + 1)
#@ @+others
#@+node:jpenner.20091212133112.8:Put
cdef inline IAch(self, int xz, int yz):
return xz + (self.w * yz)
cdef PutAch(self, int ach, int x, int y):
if not (x < 1 or y < 1 or x > self.w or y > self.h): #clip
self.rgach[self.IAch(x - 1, y - 1)] = ach
#self.mpyzxz_ach[y-1][x-1] = ach
cdef inline GetAch(self, int x, int y):
return self.rgach[self.IAch(x - 1, y - 1)]
cdef PutRgach(self, rgach, int x, int y):
cdef int xz = x - 1
cdef int iach
if xz < self.w:
if xz < 0:
rgach = rgach[min(-xz, len(rgach)):]
xz = 0
if xz + len(rgach) >= self.w:
rgach = rgach[:self.w - xz]
iach = self.IAch(xz, y - 1)
for ach in rgach:
if ach != achBlankI:
self.rgach[iach] = ach
iach = iach + 1
#self.mpyzxz_ach[y-1][xz:xz + len(rgach)] = rgach
cdef PutSt(self, char *st, int x, int y, int colFg = WHITE, int colBg=BLACK):
if y < 1 or y > self.h:
return
cdef int cch = len(st)
cdef int ichStart = 0
cdef int xz = x - 1
if xz < 0:
ichStart = (-xz)
cch = cch - ichStart
xz = 0
cch = min(cch, self.w - xz)
cdef UAch uach
uach.sach.fgCol = colFg
uach.sach.bgCol = colBg
cdef int iach = self.IAch(xz, y - 1)
for ich in range(ichStart, ichStart + cch):
uach.sach.ch = st[ich]
self.rgach[iach] = uach.ach
iach = iach + 1
#self.PutRgach([MkAch(ch, colFg, colBg) for ch in st], x, y)
cdef Fill(self, int ach, int wIn, int hIn, int x = 1, int y = 1):
if x > self.w or y > self.h or ach == achBlankI:
return
cdef int xz = max(x - 1, 0)
cdef int yz = max(y - 1, 0)
cdef int w = min(self.w - xz, wIn)
cdef int h = min(self.h - yz, hIn)
cdef int iach
for yzT in range(yz, yz + h):
iach = self.IAch(xz, yzT)
for xzT in range(w):
self.rgach[iach] = ach
iach = iach + 1
#self.mpyzxz_ach[yzT][xz:xz + w] = ach
cdef PutAscr(self, AscrI ascr, int x=1, int y=1):
if x > self.w or y > self.h:
return
cdef int xz = max(x - 1, 0)
cdef int yz = max(y - 1, 0)
cdef int w = min(self.w - xz, ascr.w)
cdef int h = min(self.h - yz, ascr.h)
cdef int yzOther = 0
cdef int iach, iachOther, ach
for yzT in range(yz, yz + h):
iach = self.IAch(xz, yzT)
iachOther = ascr.IAch(0, yzOther)
for xzT in range(w):
ach = ascr.rgach[iachOther]
if ach != achBlankI:
self.rgach[iach] = ach
iach = iach + 1
iachOther = iachOther + 1
yzOther = yzOther + 1
#@-node:jpenner.20091212133112.8:Put
#@+node:jpenner.20091212133112.9:AstDiff
cdef AstDiff(self, AscrI ascr):
assert self.w == ascr.w and self.h == ascr.h
cdef int xz = 0
cdef int yz = 0
cdef int xzPred = -1
cdef int achPrev = achInvdI
cdef int achBeforeEOL = achInvdI
cdef int achOld, achNew, achNewRaw
cdef int achSpace = MkAch(' ')
rgast = []
for iach in range(self.w * self.h):
achOld = self.rgach[iach]
achNewRaw = ascr.rgach[iach]
if achNewRaw == achBlankI:
achNew = achSpace
else:
achNew = achNewRaw
if xz == self.w - 2:
achBeforeEOL = achNew
if achOld != achNewRaw:
if xz == self.w - 1:
# Linewrap avoidance algorithm:
# when drawing the last character on a line, draw it in the space occupied by the character before.
rgast.append("%s%d;%dH" % (esc, yz + 1, xz))
rgast.append(AstFromAch(achNew, achInvdI))
# then, move the cursor back onto the character we just drew, and perform an insert.
rgast.append("%sD%s@" % (esc, esc))
# finally, draw the character before the last character in the line.
rgast.append(AstFromAch(achBeforeEOL, achNew))
else:
if xz != xzPred:
xzPred = xz
rgast.append("%s%d;%dH" % (esc, yz + 1, xz + 1))
achPrev = achInvdI
rgast.append(AstFromAch(achNew, achPrev))
achPrev = achNew
xzPred = xzPred + 1
xz = xz + 1
if xz == self.w:
xz = 0
xzPred = -1
yz = yz + 1
return "".join(rgast)
#@-node:jpenner.20091212133112.9:AstDiff
#@+node:jpenner.20091212133112.11:Hst
cdef Hst(self):
rgst = ["<pre style='font-family:\"Courier New\", Courier, System, monospace'>"]
cdef int achPrev = achInvdI
cdef int xz = 0
cdef int ach
for iach in range(self.w * self.h):
ach = self.rgach[iach]
rgst.append(HstFromAch(ach, achPrev))
achPrev = ach
xz = xz + 1
if xz == self.w:
xz = 0
rgst.append("<br>")
rgst.append("</span></pre>")
return ''.join(rgst)
#@-node:jpenner.20091212133112.11:Hst
#@-others
#@-node:jpenner.20091212133112.7:AscrI
#@+node:jpenner.20091212133112.12:FKeyPrintable
def FKeyPrintable(key):
return type(key) == str and (ord(key) >= 32 and ord(key) <= 126)
#@-node:jpenner.20091212133112.12:FKeyPrintable
#@-others
#@nonl
#@-node:jpenner.20091212133112.2:@thin ansi_cython.pyx
#@-leo

294
ansi_python.py Normal file
View file

@ -0,0 +1,294 @@
#@+leo-ver=4-thin
#@+node:jpenner.20090510085557.4:@thin ansi_python.py
#@@language python
import config
import numpy
#@+others
#@+node:jpenner.20091212133112.3:Codes
esc = '%s['%chr(27)
reset = '%s0m'%esc
cls = '%s2j'%esc
BLACK = 0
RED = 1
GREEN = 2
YELLOW = 3
BLUE = 4
MAGENTA = 5
CYAN = 6
WHITE = 7
FBRIGHT = 8
FBLINK = 16
rgcolorBg = range(8)
rgcolorFg = range(8)
rgcolorFg.extend([col | FBRIGHT for col in range(8)])
K_BACKSPACE = chr(8)
K_TAB = chr(9)
K_RETURN = chr(10)
K_DEL = chr(127)
K_LEFT = 256
K_RIGHT = 257
K_UP = 258
K_DOWN = 259
K_HOME = 260
K_END = 261
K_PGUP = 262
K_PGDN = 263
def StrKey(ch):
if type(ch) == str:
return ord(ch)
return str(ch)
def Ctrl(ch):
ch = ch.upper()
assert ch != 'M' and ch != 'J' and ch != 'H'
return chr(ord(ch - 'A' + 1))
def FEnter(key):
return key == "\n" or key == "\r"
#@nonl
#@-node:jpenner.20091212133112.3:Codes
#@+node:jpenner.20090510085557.6:Ach
# ANSI Character - contains prop and character
class Ach(object):
def __init__(self, ch, fgcol=WHITE, bgcol=BLACK):
self.ch = ch
self.fgCol = fgcol
self.bgCol = bgcol
def __eq__(self, ach):
return type(ach) is Ach and self.ch == ach.ch and self.fgCol == ach.fgCol and self.bgCol == ach.bgCol
def __ne__(self, ach):
return not (self == ach)
def MkAch(ch, fgcol=WHITE, bgcol=BLACK):
return Ach(ch, fgcol, bgcol)
def ChFromAch(ach):
return ach.ch
achBlank = Ach(' ')
achInvd = Ach(chr(255), -1, -1)
def AstFromAch(ach, achPrev = None):
ast = ach.ch
rgsgr = []
if (achPrev == None) or (achPrev.fgCol != ach.fgCol):
rgsgr.append(str((ach.fgCol & 7) + 30))
fBright = ach.fgCol & FBRIGHT
if (achPrev == None) or (fBright != achPrev.fgCol & FBRIGHT):
if fBright:
rgsgr.append("1")
else:
rgsgr.append("2")
fBlink = ach.fgCol & FBLINK
if (achPrev == None) or (fBlink != achPrev.fgCol & FBLINK):
if fBlink:
rgsgr.append("5")
else:
rgsgr.append("25")
if (achPrev == None) or (achPrev.bgCol != ach.bgCol):
rgsgr.append(str(ach.bgCol + 40))
if len(rgsgr) > 0:
ast = esc + ";".join(rgsgr) + "m" + ast
return ast
dtAch = numpy.dtype(object)
#@-node:jpenner.20090510085557.6:Ach
#@+node:jpenner.20091016050502.2:HTML
mpch_entity = [0, 9786, 9787, 9829, 9830, 9827, 9824, 8226, 9688, 9675, 9689, 9794, 9792, 9834, 9835, 9788, 9658, 9668, 8597, 8252,
182, 167, 9644, 8616, 8593, 8595, 8594, 8592, 8735, 8596, 9650, 9660, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
8962, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251,
249, 255, 214, 220, 162, 163, 165, 8359, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171,
187, 9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516,
9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554, 9555,
9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734,
966, 949, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160]
setch_unsafe = set(['&', '<', '>', '"', "'"])
mpcol_hcol = ["#000000", "#AA0000", "#00AA00", "#AA5500", "#0000AA", "#AA00AA", "#00AAAA", "#AAAAAA",
"#555555", "#FF5555", "#55FF55", "#FFFF55", "#5555FF", "#FF55FF", "#55FFFF", "#FFFFFF"]
def HstFromAch(ach, achPrev = None):
stStyle = None
if achPrev == None or achPrev.fgCol != ach.fgCol or achPrev.bgCol != ach.bgCol:
stStyle = "color:" + mpcol_hcol[ach.fgCol & 15] + ";background-color:" + mpcol_hcol[ach.bgCol & 15]
rgst = []
if stStyle != None and achPrev != None:
rgst.append("</span>")
if stStyle != None:
rgst.append("<span style='" + stStyle + "'>")
ch = ord(ach.ch)
entity = mpch_entity[ch]
if entity == ch and not ach.ch in setch_unsafe:
rgst.append(ach.ch)
else:
rgst.append("&#" + str(mpch_entity[ord(ach.ch)]) + ";")
return ''.join(rgst)
#@nonl
#@-node:jpenner.20091016050502.2:HTML
#@+node:jpenner.20090510085557.7:Pos
class Pos(object):
def __init__(self, w=config.W, h=config.H, x=1, y=1):
self.w = w
self.h = h
self.xz = x - 1
self.yz = y - 1
def X(self): return self.xz + 1
def Y(self): return self.yz + 1
def Inc(self):
if self.xz == self.w - 1:
if self.yz < self.h:
self.xz = 0
self.yz = self.yz + 1
else:
self.xz = self.xz + 1
def Up(self):
if self.yz > 0:
self.yz = self.yz - 1
def Down(self):
if self.yz < self.h - 1:
self.yz = self.yz + 1
def Left(self):
if self.xz > 0:
self.xz = self.xz - 1
def Right(self):
if self.xz < self.w - 1:
self.xz = self.xz + 1
#@-node:jpenner.20090510085557.7:Pos
#@+node:jpenner.20090510085557.8:Ascr
# ANSI Screen
class Ascr(object):
def __init__(self, w=config.W, h=config.H, achFill = None):
self.mpyzxz_ach = numpy.empty((h,w), dtAch)
self.mpyzxz_ach[:] = achFill
self.w = w
self.h = h
def Zpos(self, xz, yz):
return Pos(self.w, self.h, xz + 1, yz + 1)
def W(self): return self.w
def H(self): return self.h
#@ @+others
#@+node:jpenner.20090526105844.8:Put
def PutAch(self, ach, x, y):
if not (x < 1 or y < 1 or x > self.w or y > self.h): #clip
self.mpyzxz_ach[y-1][x-1] = ach
def GetAch(self, x, y):
return self.mpyzxz_ach[y-1][x-1]
def PutRgach(self, rgach, x, y):
xz = x - 1
if xz < self.w:
if xz < 0:
rgach = rgach[min(-xz, len(rgach)):]
xz = 0
if xz + len(rgach) >= self.w:
rgach = rgach[:self.w - xz]
self.mpyzxz_ach[y-1][xz:xz + len(rgach)] = rgach
def PutSt(self, st, x, y, colFg = WHITE, colBg=BLACK):
self.PutRgach([MkAch(ch, colFg, colBg) for ch in st], x, y)
def Fill(self, ach, w, h, x = 1, y = 1):
if x > self.w or y > self.h:
return
xz = max(x - 1, 0)
yz = max(y - 1, 0)
w = min(self.w - xz, w)
h = min(self.h - yz, h)
for yzT in range(yz, yz + h):
self.mpyzxz_ach[yzT][xz:xz + w] = ach
def PutAscr(self, ascr, x=1, y=1):
for irow, rgachRow in enumerate(ascr.mpyzxz_ach):
iachPut = -1
for iach, ach in enumerate(rgachRow):
if iachPut < 0 and ach != None:
iachPut = iach
elif iachPut >= 0 and ach == None:
self.PutRgach(rgachRow[iachPut:iach], x + iachPut, y + irow)
iachPut = -1
if iachPut >= 0:
self.PutRgach(rgachRow[iachPut:], x + iachPut, y + irow)
iachPut = -1
#@-node:jpenner.20090526105844.8:Put
#@+node:jpenner.20090527144214.3:Diff
def AstDiff(self, ascr):
assert self.w == ascr.w and self.h == ascr.h
rgast = []
achPrev = None
yz = 0
for rgachRowOld, rgachRowNew in zip(self.mpyzxz_ach, ascr.mpyzxz_ach):
xz = 0
xzPred = -1
for achOld, achNew in zip(rgachRowOld, rgachRowNew):
if xz == self.w - 2:
achBeforeEOL = achNew
if achOld != achNew:
achNew = achNew or achBlank
if xz == self.w - 1:
# Linewrap avoidance algorithm:
# when drawing the last character on a line, draw it in the space occupied by the character before.
rgast.append("%s%d;%dH" % (esc, yz + 1, xz))
rgast.append(AstFromAch(achNew, None))
# then, move the cursor back onto the character we just drew, and perform an insert.
rgast.append("%sD%s@" % (esc, esc))
# finally, draw the character before the last character in the line.
rgast.append(AstFromAch(achBeforeEOL or achBlank, achNew))
else:
if xz != xzPred:
xzPred = xz
rgast.append("%s%d;%dH" % (esc, yz + 1, xz + 1))
achPrev = None
rgast.append(AstFromAch(achNew, achPrev))
achPrev = achNew
xzPred = xzPred + 1
xz = xz + 1
yz = yz + 1
return "".join(rgast)
#@nonl
#@-node:jpenner.20090527144214.3:Diff
#@+node:jpenner.20090529173104.26:Ast
def Ast(self):
return Ascr(self.w, self.h, achInvd).AstDiff(self) #stupid implementation
#@nonl
#@-node:jpenner.20090529173104.26:Ast
#@+node:jpenner.20091016050502.3:Hst
def Hst(self):
rgst = ["<pre>"]
achPrev = None
for rgachRow in self.mpyzxz_ach:
for ach in rgachRow:
rgst.append(HstFromAch(ach or achBlank, achPrev))
achPrev = ach or achBlank
rgst.append("<br>")
rgst.append("</span></pre>")
return ''.join(rgst)
#@nonl
#@-node:jpenner.20091016050502.3:Hst
#@-others
#@-node:jpenner.20090510085557.8:Ascr
#@+node:jpenner.20090521203229.341:FKeyPrintable
def FKeyPrintable(key):
return type(key) == str and (ord(key) >= 32 and ord(key) <= 126)
#@-node:jpenner.20090521203229.341:FKeyPrintable
#@-others
#@nonl
#@-node:jpenner.20090510085557.4:@thin ansi_python.py
#@-leo

27
auth.py Normal file
View file

@ -0,0 +1,27 @@
#@+leo-ver=4-thin
#@+node:jpenner.20090607135901.1:@thin auth.py
import MySQLdb
import hashlib
import config
class NoopAuth(object):
def FAuthorized(self, user, passwd):
return True
class DrupalAuth(object):
def FAuthorized(self, user, passwd):
conn = MySQLdb.connect(host = config.drupaldb_host, user = config.drupaldb_user, passwd = config.drupaldb_password, db = config.drupaldb)
try:
cursor = conn.cursor()
try:
cursor.execute("SELECT name, pass FROM users WHERE name = %s AND pass = %s", (user, hashlib.md5(passwd).hexdigest()))
return cursor.fetchone() != None
finally:
cursor.close()
except Exception:
return False
finally:
conn.close()
#@-node:jpenner.20090607135901.1:@thin auth.py
#@-leo

826
basetoken.py Normal file
View file

@ -0,0 +1,826 @@
from engine import *
import config
from zope.interface import implements, Interface
import weakref
from util import *
class Blinker(Token):
def InitPersistent(self, owner, setter, rgVal = [True, False], interval = 500):
Token.InitPersistent(self, owner)
self.setter = setter
self.rgVal = rgVal
self.interval = interval
def run(self):
while True:
for val in self.rgVal:
self.setter(val)
self.wait(self.interval)
class StaticGraphic(Token):
def InitPersistent(self, owner, ascr, pos, *rgtag):
Token.InitPersistent(self, owner)
self.pos = pos
self.tag("drawable", *rgtag)
self.ascr = ascr
def draw(self, ascr, client):
ascr.PutAscr(self.ascr, self.pos[0], self.pos[1])
class AnimatedGraphic(StaticGraphic):
def InitPersistent(self, owner, rgascr, pos, interval, *rgtag):
StaticGraphic.InitPersistent(self, owner, rgascr[0], pos, *rgtag)
Blinker(self, self.setAscr, rgascr, interval)
def setAscr(self, ascr):
self.ascr = ascr
class Terminal(Token):
def InitPersistent(self, owner, client, w = config.W, h = config.H):
Token.InitPersistent(self, owner, "drawable", "background")
self.client = client
self.x = 0
self.y = 0
self.w = w
self.h = h
self.fWrapHoriz = False
self.fWrapVert = True
self.stLine = None
self.xLine = None
self.yLine = None
self.screen = []
self.fBlink = False
self.colBg = ansi.BLUE
self.chEcho = None
for y in range(h):
self.screen.append("")
Blinker(self, self.setBlink)
def setBlink(self, fBlink):
self.fBlink = fBlink
def getKey(self):
return self.client.evKey.receive(self)
def getPrintableKey(self):
while True:
key = self.getKey()
if ansi.FKeyPrintable(key):
return key
def deleteCh(self):
stOld = self.screen[self.y]
self.screen[self.y] = stOld[0:self.x] + stOld[self.x + 1:]
def printSt(self, st):
stOld = self.screen[self.y]
stNew = stOld[0:self.x] + st + stOld[self.x+len(st):]
self.screen[self.y] = stNew
self.moveTo(self.x + len(st), self.y)
def moveTo(self, x, y):
self.x = x
self.y = y
while (self.x >= self.w):
if (self.fWrapHoriz):
self.y = self.y + 1
self.x = self.x - self.w
else:
self.x = self.w - 1
while (self.x < 0):
self.y = self.y - 1
self.x = self.x + self.w
if (self.y < 0):
self.y = 0
while (self.fWrapVert and self.y >= self.h):
self.screen = self.screen[1:]
self.screen.append("")
self.y = self.y - 1
self.screen[self.y] = self.screen[self.y].ljust(self.x)
def type(self, st):
self.client.beep()
for iSt in range(len(st)):
self.printSt(st[iSt:iSt + 1])
self.wait(35)
def typeLn(self, st):
self.type(st)
self.newLine()
def centerLn(self, st):
self.typeLn(st.rjust((self.w / 2) + (len(st) / 2)))
def getLine(self):
self.xLine = self.x
self.yLine = self.y
self.stLine = ""
fWrapHorizStart = self.fWrapHoriz
self.fWrapHoriz = False
while True:
key = self.getKey()
fBeep = True
if (key == ansi.K_BACKSPACE and self.x > self.xLine):
self.stLine = self.stLine[:self.x - self.xLine - 1] + self.stLine[self.x - self.xLine:]
self.moveTo(self.x - 1, self.y)
elif (key == ansi.K_LEFT and self.x > self.xLine):
self.moveTo(self.x - 1, self.y)
elif (key == ansi.K_RIGHT):
self.moveTo(self.x + 1, self.y)
if (self.x - self.xLine) > len(self.stLine):
self.stLine = self.stLine + " "
elif (ansi.FKeyPrintable(key)):
self.stLine = self.stLine[:self.x - self.xLine] + key + self.stLine[(self.x + 1) - self.xLine:]
self.moveTo(self.x + 1, self.y)
elif key == ansi.K_RETURN:
break
else:
print "weird key", ansi.StrKey(key)
fBeep = False
if fBeep:
self.client.beep()
self.fWrapHoriz = fWrapHorizStart
x,y = self.x, self.y
self.moveTo(self.xLine, self.yLine)
self.printSt(self.StLineDisp())
self.moveTo(x,y)
stLine = self.stLine.strip()
self.stLine = None
self.xLine = None
self.yLine = None
return stLine
def StLineDisp(self):
return self.stLine if not self.chEcho else self.chEcho * len(self.stLine)
def draw(self, ascr, client):
if client == self.client:
y = 1
for line in self.screen:
ascr.PutSt("{0:{1}}".format(line, self.w), 1, y, ansi.WHITE | ansi.FBRIGHT, self.colBg)
y = y + 1
if self.stLine:
ascr.PutSt(self.StLineDisp(), self.xLine + 1, self.yLine + 1, ansi.WHITE | ansi.FBRIGHT, self.colBg)
if (self.fBlink):
ascr.PutAch(ansi.MkAch(" ", ansi.WHITE | ansi.FBRIGHT, ansi.WHITE), self.x + 1, self.y + 1)
def spin(self, stSpin):
self.moveTo(self.x - 1, self.y)
self.printSt(stSpin)
def newSpinner(self):
return Blinker(self.game, self.spin, ["/","-","\\", "|"], 100)
def newLine(self, count = 1, wait = 0):
for i in range(count):
self.moveTo(0, self.y + 1)
self.beep()
self.wait(wait)
def beep(self):
self.client.beep()
def setColBg(self, colBg):
self.colBg = colBg
class AutoJoiner(Token):
def InitPersistent(self, owner, *rgclsTok):
Token.InitPersistent(self, owner)
self.rgclsTok = rgclsTok
def InitTransient(self):
Token.InitTransient(self)
self.mpclient_rgtok = {}
def run(self):
def dgoobLeave(client):
for tok in self.mpclient_rgtok[client]:
print "killing ", tok
tok.die()
while True:
with self.game.evLeave.oob(self, dgoobLeave):
client = self.game.evJoin.receive(self)
rgtok = []
for clsTok in self.rgclsTok:
if FIter(clsTok):
tok = clsTok[0](self.game, client, *clsTok[1:])
else:
tok = clsTok(self.game, client)
rgtok.append(tok)
self.mpclient_rgtok[client] = rgtok
class AliveWithPlayers(Token):
def InitPersistent(self, owner, *rgclsTok):
Token.InitPersistent(self, owner)
self.rgclsTok = rgclsTok
def InitTransient(self):
Token.InitTransient(self)
self.rgclient = []
def OnLeave(self, client):
self.rgclient.remove(client)
if len(self.rgclient) == 0:
for tok in [x for x in self.rgtokOwn]:
tok.die()
def run(self):
with self.game.evLeave.oob(self, self.OnLeave):
while True:
self.rgclient.append(self.game.evJoin.receive(self))
if len(self.rgclient) == 1:
for clsTok in self.rgclsTok:
if FIter(clsTok):
tok = clsTok[0](self, clsTok[1:])
else:
tok = clsTok(self)
class AutoKiller(Token):
def InitTransient(self):
Token.InitTransient(self)
self.rgclient = []
def OnLeave(self, client):
self.rgclient.remove(client)
if len(self.rgclient) == 0:
self.game.finish()
def run(self):
with self.game.evLeave.oob(self, self.OnLeave):
while True:
self.rgclient.append(self.game.evJoin.receive(self))
#selection oracle
class Selor(TPrs):
NONE = 0
PRI = 1
SEC = 2
def __init__(self, mi, selorParent, rgmiSec, fPri):
self.selorParent = selorParent
self.mi = mi
self.rgmiSec = rgmiSec
self.fPri = fPri
def MiParent(self):
if self.selorParent != None:
return self.selorParent.mi
return None
def KSel(self):
if self.fPri:
return self.PRI
elif self.mi in self.rgmiSec:
return self.SEC
else:
return self.NONE
def SelorChild(self, miChild, fPri):
return Selor(miChild, self, self.rgmiSec, self.fPri and fPri)
def SelorDeselect(self):
return Selor(self.mi, self.selorParent, self.rgmiSec, False)
class Mi(TPrs):
def InitPersistent(self):
self.miParent = None
self.fNotice = False
self.rgmiNotice = [self]
def Height(self, w):
return 1
def StName(self):
return "Unnamed"
def StKey(self):
return self.StName()
def HandleKey(self, key):
return False
def FIgnoreParent(self):
return False
def DrawWithParent(self, selorParent, ascr, x, y, w, fPri):
self.Draw(ascr, x, y, w, selorParent.SelorChild(self, fPri))
def ColBgDefault(self):
return ansi.BLUE
def ColBgSelected(self, fPri):
return ansi.YELLOW if fPri else ansi.CYAN
def ColBgNotice(self):
return ansi.CYAN
def ColBg(self, selor):
if selor != None and selor.KSel() != Selor.NONE:
if selor.KSel() == Selor.PRI:
for mi in self.rgmiNotice:
if mi != self and mi.fNotice:
print "Notice cleared for ", mi.StName(), "by ", self.StName()
mi.fNotice = False
return self.ColBgSelected(True)
else:
return self.ColBgSelected(False)
elif self.FNoticeFlagged():
return self.ColBgNotice()
elif not self.FIgnoreParent() and selor != None and selor.MiParent() != None:
return selor.MiParent().ColBg(selor.selorParent.SelorDeselect())
else:
return self.ColBgDefault()
def ColFg(self):
return ansi.WHITE | ansi.FBRIGHT
def FlagNotice(self):
self.fNotice = True
def ListenForNotice(self, mi):
self.rgmiNotice.append(mi)
def FNoticeFlagged(self):
for mi in self.rgmiNotice:
if mi.fNotice:
return True
return False
def FSelectable(self):
return True
class MiInvisible(Mi):
def Height(self, w):
return 0
def Draw(self, *rgarg):
pass
def FSelectable(self):
return False
miInvisible = MiInvisible()
class MiStatic(Mi):
def InitPersistent(self, stText):
Mi.InitPersistent(self)
self.stText = stText
def StName(self):
return self.stText
def FSelectable(self):
return False
def Height(self, w):
return len(RgstWrapped(self.StName(), w, 0))
def Draw(self, ascr, x, y, w, selor):
for st in RgstWrapped(self.StName(), w, 0):
ascr.PutSt("{0:^{1}}".format(st, w), x, y, self.ColFg(), self.ColBg(selor))
y = y + 1
class MiDgText(MiStatic):
def InitPersistent(self, dgText):
MiStatic.InitPersistent(self, None)
self.dgText = dgText
def StName(self):
return self.dgText()
class MiButton(MiStatic):
def InitPersistent(self, stName, dgCmd, value = None):
MiStatic.InitPersistent(self, stName)
self.dgCmd = dgCmd
self.value = value
def StName(self):
if self.stText == None and self.value != None:
return self.value.StName()
return self.stText
def Exec(self):
return self.dgCmd()
def FSelectable(self):
return True
def HandleKey(self, key):
if ansi.FEnter(key) or key == ' ':
return self.Exec()
return False
def Value(self):
return self.value
class MiToggle(MiButton):
def InitPersistent(self, stName, fInitial = False):
MiButton.InitPersistent(self, stName, None, fInitial)
def Exec(self):
self.value = not self.value
return True
def StName(self):
stPre = "[X] " if self.value else "[ ] "
return stPre + self.stText
def StKey(self):
return self.stText
class MiList(Mi):
def InitPersistent(self, rgval, ival = 0):
Mi.InitPersistent(self)
self.rgval = rgval
self.ival = ival
def Value(self):
return self.rgval[self.ival]
def Inc(self):
if self.ival < len(self.rgval) - 1:
self.ival = self.ival + 1
def Dec(self):
if self.ival > 0:
self.ival = self.ival - 1
def HandleKey(self, key):
if key == ansi.K_LEFT:
self.Dec()
elif key == ansi.K_RIGHT:
self.Inc()
else:
return False
return True
def Draw(self, ascr, x, y, w, selor):
xText = w / 4
xVal = w / 2
ascr.PutSt(self.StName() + ":", xText, y, self.ColFg(), self.ColBg(selor))
self.DrawValue(ascr, xVal, y, selor.SelorDeselect())
class MiTypein(Mi):
def InitPersistent(self, dgEnter, stName = "Typein", pctW = 100):
Mi.InitPersistent(self)
self.stedit = Stedit(dgEnter)
self.stName = stName
self.pctW = pctW
assert pctW > 0 and pctW <= 100
def StName(self):
return self.stName
def Value(self):
return self.stedit.GetValue()
def SetValue(self, st):
self.stedit.SetValue(st)
def HandleKey(self, key):
return self.stedit.HandleKey(key)
def ColBgDefault(self):
return ansi.BLACK
def ColBgSelected(self, fPri):
return ansi.WHITE if fPri else ansi.BLUE
def ColFg(self):
return ansi.WHITE
def FIgnoreParent(self):
return True
def Height(self, wT):
return len(RgstWrapped(self.GetStToWrap(), self.GetW(wT)))
def GetW(self, wT):
return int(wT * (self.pctW / 100.0))
def GetStToWrap(self):
return self.stedit.StForSize()
def Draw(self, ascr, xT, y, wT, selor):
w = self.GetW(wT)
x = xT + ((wT - w) / 2)
if selor.KSel() != Selor.NONE:
stToWrap = self.GetStToWrap()
else:
stToWrap = self.stedit.GetValue()
for snippet in RgSnippetWrapped(stToWrap, w):
ascr.PutSt("{0:{1}}".format(snippet.st, w), x, y, self.ColFg(), self.ColBg(selor.SelorDeselect()))
if selor.KSel() != Selor.NONE:
self.stedit.DrawCursor(ascr, x, y, self.ColFg(), self.ColBg(selor), snippet)
y = y + 1
class MiTab(MiStatic):
def InitPersistent(self, stText, mi):
MiStatic.InitPersistent(self, stText)
self.mi = mi
self.ListenForNotice(mi)
def Value(self):
return self.mi
def FSelectable(self):
return True
@staticmethod
def MiTabbed(*rgstTab_mi):
miTabRow = MiMenuHoriz([MiTab(*stTab_mi) for stTab_mi in rgstTab_mi])
return MiMenu([miTabRow, MiTabBody(miTabRow)])
class MiTabBody(Mi):
def InitPersistent(self, miMenu):
Mi.InitPersistent(self)
self.miMenu = miMenu
def Mi(self):
return self.miMenu.Value()
def HandleKey(self, key):
return self.Mi().HandleKey(key)
def Draw(self, ascr, x, y, w, selor):
self.Mi().Draw(ascr, x, y, w, selor)
def Height(self,w):
return self.Mi().Height(w)
class MiValue(Mi):
def InitPersistent(self, mi):
Mi.InitPersistent(self)
self.mi = mi
def StName(self):
return self.mi.StName()
def Value(self):
return self.mi.Value()
def Height(self,w):
return self.mi.Height(w)
def Draw(self, ascr, x, y, w, selor):
self.mi.DrawValue(ascr, x, y, selor.SelorChild(self.mi, False))
class Selection(TPrs):
def InitPersistent(self, rgo, o = None, io = 0):
self.rgo = rgo
self.o = o
self.io = -1 if o == None else io
self.Validate()
def Invalidate(self):
self.o = None
self.io = -1
def Validate(self):
# aw hell, selection only handles inserts, not deletes :(
if self.o == None or self.io < 0:
self.Invalidate()
elif len(self.rgo) <= self.io or self.rgo[self.io] != self.o:
try:
self.io = self.rgo.index(self.o)
except Exception:
self.Invalidate()
if self.o == None and not self.FEmpty():
self.io = IoInc(self.rgo, self.io, self.FSelectableI)
self.o = self.rgo[self.io]
def GetSelected(self):
self.Validate()
return self.o
def SetSelected(self, o):
self.o = o
self.Validate()
def ITopScroll(self, h, dgHeight):
# requirements:
# selection must be visible
# if possible, selection should be centered
if self.io < 0:
return 0
iotop = self.io
iobot = self.io
hCurr = dgHeight(self.o)
yobot = hCurr
fGrowUp = False
while hCurr < h:
fDoneUp = iotop == 0
fDoneDown = iobot == len(self.rgo) - 1
if (fGrowUp or fDoneDown) and not fDoneUp:
ho = dgHeight(self.rgo[iotop - 1])
if (yobot + ho >= h): # handle case where thing above selected thing is huge and pushes the selection off the screen
break
iotop = iotop - 1
yobot = yobot + ho
elif not fDoneDown:
ho = dgHeight(self.rgo[iobot + 1])
iobot = iobot + 1
else:
break
hCurr = hCurr + ho
fGrowUp = not fGrowUp
return iotop
def Inc(self):
return self.ChangeI(IoInc)
def Dec(self):
return self.ChangeI(IoDec)
def FEmpty(self):
for o in self.rgo:
if self.FSelectableI(o):
return False
return True
def ChangeI(self, fnChange):
self.Validate()
if self.o != None:
ioT = self.io
self.io = fnChange(self.rgo, self.io, self.FSelectableI)
self.o = self.rgo[self.io]
return ioT != self.io
def FSelectableI(self, o):
return o != None and o.FSelectable()
class MiMenuI(Mi):
def InitPersistent(self, rgmi):
Mi.InitPersistent(self)
self.selMi = Selection(rgmi)
self.mpstName_mi = {}
for mi in rgmi:
if mi != None:
self.mpstName_mi[mi.StKey().lower()] = mi
def Value(self, stKey = None):
if stKey == None:
return self.selMi.GetSelected().Value()
return self.mpstName_mi[stKey.lower()].Value()
def MiByName(self, stKey):
return self.mpstName_mi[stKey.lower()]
def HeightMi(self, mi, w):
if mi == None:
return 1
return mi.Height(w)
def ColBgSelected(self, fPri):
return self.ColBgDefault()
class MiMenu(MiMenuI):
def InitPersistent(self, rgmi, hMax = -1):
MiMenuI.InitPersistent(self, rgmi)
self.hMax = hMax
def HandleKey(self, key):
mi = self.selMi.GetSelected()
if mi == None or not mi.HandleKey(key):
if key == ansi.K_DOWN:
return self.selMi.Inc()
elif key == ansi.K_UP:
return self.selMi.Dec()
return False
return True
def HMax(self, ascr, y):
if self.hMax < 0:
return (ascr.H() - y) + 1
return self.hMax
def Height(self, w):
return sum([self.HeightMi(mi,w) for mi in self.selMi.rgo])
def Draw(self, ascr, x, y, w, selor):
ascr.Fill(ansi.MkAch(' ', self.ColFg(), self.ColBg(selor)), w, self.Height(w), x, y)
miSelected = self.selMi.GetSelected()
h = 0
hMax = self.HMax(ascr, y)
itop = self.selMi.ITopScroll(hMax, lambda mi: self.HeightMi(mi, w))
for imi, mi in enumerate(self.selMi.rgo):
if imi < itop:
continue
if mi != None:
mi.DrawWithParent(selor, ascr, x, y + h, w, miSelected == mi)
h = h + self.HeightMi(mi, w)
if h >= hMax:
break
class MiMenuHoriz(MiMenuI):
def InitPersistent(self, rgmi, rgsize = None):
MiMenuI.InitPersistent(self, rgmi)
if rgsize == None:
rgsize = [1 for mi in rgmi]
self.rgsize = rgsize
self.sizeMax = float(sum(rgsize))
def Width(self, imi, w):
return int((self.rgsize[imi] / self.sizeMax) * w)
def HandleKey(self, key):
mi = self.selMi.GetSelected()
if mi == None or not mi.HandleKey(key):
if key == ansi.K_RIGHT:
return self.selMi.Inc()
elif key == ansi.K_LEFT:
return self.selMi.Dec()
return False
return True
def Height(self, w):
return max([self.HeightMi(mi, w) for mi in self.selMi.rgo])
def Draw(self, ascr, x, y, w, selor):
ascr.Fill(ansi.MkAch(' ', self.ColFg(), self.ColBg(selor)), w, self.Height(w), x, y)
miSelected = self.selMi.GetSelected()
for imi, mi in enumerate(self.selMi.rgo):
wT = self.Width(imi, w)
if mi != None:
mi.DrawWithParent(selor, ascr, x, y, wT, miSelected == mi)
x = x + wT
def DgProjectMiButton(dgExec):
def DgProject(value):
return MiButton(None, lambda: dgExec(value), value)
return DgProject
class RgmiProjected(TPrs):
def InitPersistent(self, rgvalue, dgProject):
self.rgvalue = rgvalue
self.dgProject = dgProject
def InitTransient(self):
self.mpvalue_wrmi = weakref.WeakKeyDictionary()
def __getitem__(self, i):
return self.MiFromValue(self.rgvalue[i])
def MiFromValue(self, value):
if value in self.mpvalue_wrmi:
mi = self.mpvalue_wrmi[value]()
if mi != None:
return mi
mi = self.dgProject(value)
mi._valueProjected = value
self.mpvalue_wrmi[value] = weakref.ref(mi) # this probably gc's much more than is necessary ... :/
return mi
def __len__(self):
return len(self.rgvalue)
def index(self, mi):
return self.rgvalue.index(mi._valueProjected)
class OvStatic(TokenClient):
TOP = 1
MIDDLE = 2
BOTTOM = 3
FILL = 4
def InitPersistent(self, owner, client, miMenu, kplace, *rgtag):
TokenClient.InitPersistent(self, owner, client, "drawable", "menu", *rgtag)
self.miMenu = miMenu
self.kplace = kplace
self.mpst_miSel = {}
def SetSelection(self, stSel, mi):
self.mpst_miSel[stSel] = mi
def GetSelection(self, stSel):
try:
return self.mpst_miSel[stSel]
except KeyError:
return None
def draw(self, ascr, client):
self.drawI(ascr, client, False)
def drawI(self, ascr, client, fSelected):
if client == self.client:
selor = Selor(self.miMenu, None, self.mpst_miSel.values(), fSelected)
if self.kplace & self.FILL:
h = ascr.H()
y = 1
dh = h - self.miMenu.Height(ascr.W())
if dh > 0:
ascr.Fill(ansi.MkAch(' ', self.miMenu.ColFg(), self.miMenu.ColBg(selor)), ascr.W(), dh, 1, ascr.H() - dh + 1)
else:
h = self.miMenu.Height(ascr.W())
if self.kplace == self.TOP:
y = 1
elif self.kplace == self.MIDDLE:
y = (ascr.H() / 2) - (h / 2)
else: # BOTTOM
y = ascr.H() - h + 1
self.miMenu.Draw(ascr, 1, y, ascr.W(), selor)
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))
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")
self.evShow = Event(self.game)
self.evDone = Event(self.game)
self.fAwake = False
def run(self):
while True:
self.evShow.receive(self)
self.fAwake = True
while self.fAwake:
key = self.client.evKey.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
self.evDone.fire()
def draw(self, ascr, client):
if self.fAwake:
self.drawI(ascr, client, True)
class MsgScroller(Token):
def InitPersistent(self, owner, colFg=ansi.BLUE, colBg=ansi.BLACK, y=config.H):
Token.InitPersistent(self, owner, "drawable", "msgscroller", "overlay")
self.colFg = colFg
self.colBg = colBg
self.rgmsg = []
self.msg = None
self.evPost = Event(self.game)
self.y = y
def postI(self, msg):
self.rgmsg.append(msg)
def run(self):
while True:
self.postI(self.evPost.receive(self))
with self.evPost.oob(self, self.postI):
while len(self.rgmsg) > 0:
self.msg = self.rgmsg[0]
self.rgmsg = self.rgmsg[1:]
self.x = config.W
while self.x > -len(self.msg):
self.x = self.x - 1
self.wait(30)
self.msg = None
def draw(self, ascr, client):
if self.msg:
ascr.PutSt(self.msg, self.x, self.y, self.colFg, self.colBg)

16
build_entity.py Normal file
View file

@ -0,0 +1,16 @@
#@+leo-ver=4-thin
#@+node:jpenner.20091016050502.1:@thin build_entity.py
import re
reEnt = re.compile(r"^.*&#(\d+);.*$");
mpch_entity = [0]
with open("cp437_html.txt") as fp:
for line in fp.readlines():
ent = reEnt.match(line).group(1)
mpch_entity.append(int(ent))
print "mpch_entity = ", mpch_entity
#@nonl
#@-node:jpenner.20091016050502.1:@thin build_entity.py
#@-leo

23
config.py Normal file
View file

@ -0,0 +1,23 @@
# Port to run the telnet server on.
PORT_TELNET = 19999
# Port to run the flash policy server on. Set to None to turn off.
PORT_FLASHPOLICY = 20001
# Hostname to bind servers on. Leave as "" for all.
BIND_HOSTNAME = ""
# width and height; default 80x25
W = 80
H = 25
# directory to save ANSI pictures to. leave as "." for current directory. no trailing slash required. "" == /
DIR_ANSI = "."
# authorization. Options are "Noop" (make up a username, no password), "Drupal" (fetches from MySQL Drupal database)
AUTH = "Noop"
# if Drupal, configure these options:
#drupaldb = "database"
#drupaldb_user = "user"
#drupaldb_password = "password"
#drupaldb_host = "localhost"
# Port to run the command server on. Set to None to turn off. Only set this port for testing: it will allow anyone to take down the server!
PORT_CMDSERVER = 20002
# Flag whether we should build and use Cython modules to improve performance.
USE_CYTHON = True

517
engine.py Normal file
View file

@ -0,0 +1,517 @@
import stackless
import random
import logging
import pickle
import time
import ansi
import auth
import config
import telnet
import traceback
from twisted.internet import reactor
from tpers import TPrs, TPLS, Version
import tpers
class Event(TPrs):
def InitPersistent(self, game):
self.game = game
def InitTransient(self):
self.rgtk = TPLS()
self.stkValue = []
def oob(self, tok, dgoob):
return Oob(self, tok, dgoob)
def receive(self, tok):
chNotify = tok.chEv
self.rgtk.append(tok)
while True:
ev, value = chNotify.receive()
if ev == self:
return value
ev.rgtk.append(tok)
if ev in tok.mpevDgoob and tok.mpevDgoob[ev](value):
raise Event.OobBreakException()
def fire(self, value = None):
self.stkValue.append(value)
self.game.queueEv.append(self)
self.game.ensureRun()
def fireI(self):
rgtkOld = self.rgtk
value = self.stkValue[0]
self.stkValue = self.stkValue[1:]
self.rgtk = TPLS()
for tk in rgtkOld:
if tk.fRunning:
tk.chEv.send((self,value))
stackless.run()
class Oob(object):
def __init__(self, ev, tok, dgoob):
self.ev = ev
self.tok = tok
self.dgoob = dgoob
def __enter__(self):
self.ev.rgtk.append(self.tok)
self.tok.mpevDgoob[self.ev] = self.dgoob
def __exit__(self, etype, eval, tb):
if etype != TaskletExit:
try:
self.tok.mpevDgoob.pop(self.ev)
self.ev.rgtk.remove(self.tok)
if etype == OobBreakException:
return True
except Exception:
print "exception exiting oob:"
traceback.print_exc()
print "oob:", etype, eval
traceback.print_tb(tb)
class OobBreakException(Exception):
pass
class Runner(TPrs):
def InitPersistent(self):
self.mpuser_cld = {}
print "New Runner created"
def InitTransient(self):
self.rgclient = []
def GetCld(self, user):
cld = self.mpuser_cld.get(user)
if cld == None:
cld = Cld(user)
self.mpuser_cld[user] = cld
return cld
def RunGameI(self, client):
client.runner = self
self.rgclient.append(client)
def OnDisconnect():
self.rgclient.remove(client)
client.addDgQuit(OnDisconnect)
return self.RunGame(client)
def RunServer(self):
for client in self.rgclient:
client.quit(True)
telnet.RunServer(self.RunGameI)
def Run(clsRunner, fn):
runner = tpers.Odb.Load(fn) or clsRunner()
def ExecCmd(stCmd):
if stCmd == "save":
tpers.Odb.Save(runner, fn)
return "Saved to " + fn
return "Unrecognized command: '" + stCmd + "'"
telnet.RunCmdServer(ExecCmd)
runner.RunServer()
class Ownable(TPrs):
def InitPersistent(self, owner = None):
self.owner = owner
self.rgtokOwn = TPLS()
if owner != None:
owner.rgtokOwn.append(self)
def FPersist(self):
if self.owner != None and not self.owner.FPersist():
return False
return TPrs.FPersist(self)
def die(self):
if self.owner != None:
self.owner.rgtokOwn.remove(self)
for tok in [x for x in self.rgtokOwn]:
tok.die()
self.DontPersist()
@Version(2)
class Game(Ownable):
def InitPersistent(self):
Ownable.InitPersistent(self)
self.fQuit = False
self.running = False
self.mptagTokenset = {}
self.rgdgdie = []
self.evJoin = Event(self)
self.evLeave = Event(self)
self.mpuser_cldg = {}
self.CreateRgtok(self.GetRgclsTokPers(), True)
def InitTransient(self):
self.MakeTransient("fScheduled", False)
self.rgclient = []
self.rgproc = [PTimer(), PEvent(), PDraw(*self.GetRgtagDraw())]
for proc in self.rgproc:
proc.setGame(self)
# don't recreate tokens when game has died (shouldn't even be persisting)
if not self.FDead():
self.CreateRgtok(self.GetRgclsTokTrans(), False)
else:
print "Dead", self.__class__, "has persisted"
def FDead(self):
try:
rc = self.rc
return True
except:
return False
def GetCldg(self, user):
cldg = self.mpuser_cldg.get(user)
if cldg == None:
cldg = Cldg()
self.mpuser_cldg[user] = cldg
return cldg
def GetRgclsTokPers(self):
return []
def GetRgclsTokTrans(self):
return []
def GetRgtagDraw(self):
return ["background", "solid", "overlay"]
def CreateRgtok(self, rgclsTok, fPersist):
for clsTok in rgclsTok:
if FIter(clsTok):
tok = clsTok[0](self, *clsTok[1:])
else:
tok = clsTok(self)
if not fPersist:
tok.DontPersist()
def tagToken(self, token, tag):
if not (tag in self.mptagTokenset):
self.mptagTokenset[tag] = set([token])
else:
self.mptagTokenset[tag].add(token)
def untagToken(self, token, tag):
if tag in self.mptagTokenset:
self.mptagTokenset[tag].discard(token)
def rgtoken(self, tag, rgpriority = []):
if not (tag in self.mptagTokenset):
return []
rgtoken = []
tokenSet = self.mptagTokenset[tag].copy()
for priority in rgpriority:
if (priority in self.mptagTokenset):
ptokenSet = self.mptagTokenset[priority] & tokenSet
for token in ptokenSet:
rgtoken.append(token)
tokenSet -= ptokenSet
for token in tokenSet:
rgtoken.append(token)
return rgtoken
def quit(self):
self.running = False
self.fQuit = True
def finish(self, rc = None):
self.running = False
self.rc = rc
class QuitException(Exception):
pass
class LoadException(Exception):
pass
def die(self):
for dgdie in self.rgdgdie:
dgdie()
Ownable.die(self)
def runStep(self):
try:
if self.running:
for proc in self.rgproc:
proc.process()
if not self.running:
self.die()
for client in self.rgclient:
client.leaveGame(self.rc)
for client in self.rgclient:
client.postRunStep()
finally:
self.fScheduled = False
return self.running
def joinGame(self,client):
self.rgclient.append(client)
self.evJoin.fire(client)
def leaveGame(self, client):
self.evLeave.fire(client)
def leaveGameI(self, client):
self.rgclient.remove(client)
def ensureRun(self):
self.running = True
if not self.fScheduled:
self.fScheduled = True
reactor.callLater(0, self.runStep)
def UpgradeFrom(self, versionOld):
if versionOld < 2:
self.mpuser_cldg = {}
# Client data
@Version(2)
class Cld(TPrs):
def InitPersistent(self, user):
self.user = user
def UpgradeFrom(self, versionOld):
if versionOld < 2:
del self.mpgame_cldg
#per-game client data
class Cldg(TPrs):
def FPersist(self):
if len(self._persistent) == 0:
return False
return TPrs.FPersist(self)
class Client(TPrs):
def InitTransient(self):
self.chRun = stackless.channel()
self.gameCurr = None
self.chCont = None
self.fRunning = False
self.dgJoinGame = None
self.rgdgQuit = []
self.fQuit = False
self.cld = None
self.runner = None
def FPersist(self):
return False
def go(self, fnRun, protocol):
self.protocol = protocol
self.tskRun = stackless.tasklet(fnRun)
self.tskRun(self)
if self._runTskRun():
self.gameCurr.ensureRun()
def joinGame(self, game):
assert not self.fRunning, "already running"
chCont = stackless.channel()
self.chRun.send((game, chCont))
return chCont.receive()
def leaveGame(self, rc = None):
self.fRunning = False
self.gameCurr.leaveGame(self)
self.rc = rc
def quit(self):
self.leaveGame(None)
self.fQuit = True
def _runTskRun(self):
"run self.tskRun after it has been scheduled, and await results"
stackless.run()
if not self.tskRun.scheduled:
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.fQuit:
self.chCont.send(self.rc)
self.fQuit = not self._runTskRun()
if self.fQuit:
for dgQuit in self.rgdgQuit:
dgQuit()
return self.fQuit
def beep(self):
pass
def login(self, user, passwd):
authr = getattr(auth, config.AUTH + "Auth")()
if (authr.FAuthorized(user, passwd)):
self.cld = self.runner.GetCld(user)
return True
return False
def addDgQuit(self, dgquit):
self.rgdgQuit.append(dgquit)
def removeDgQuit(self, dgquit):
self.rgdgQuit.remove(dgquit)
def Cldg(self, game = None):
if game == None:
game = self.gameCurr
return game.GetCldg(self.cld.user)
class Processor(TPrs):
def setGame(self, game):
self.game = game
def process(self):
pass
class PTimer(Processor):
def msNow(self):
return int(time.time() * 1000)
def setGame(self, game):
self.game = game
self.fReset = False
game.evTick = Event(game)
game.ms = 0
game.msDelta = 0
self.dms = -self.msNow()
def __setstate__(self, dict):
Processor.__setstate__(self, dict)
self.fReset = True
def process(self):
if self.fReset:
# keep game.ms constant
self.dms = self.game.ms - self.msNow()
self.fReset = False
msNew = self.msNow() + self.dms
self.game.msDelta = msNew - self.game.ms
self.game.ms = msNew
self.game.evTick.fire(self.game.msDelta)
class PEvent(Processor):
def setGame(self, game):
self.game = game
game.queueEv = []
game.rgdgdie.append(self.die)
def die(self):
for ev in self.game.queueEv:
for tk in ev.rgtk:
tk.die()
ev.stkValue = []
self.game.queueEv = []
def process(self):
while self.game.queueEv:
self.game.queueEv[0].fireI()
self.game.queueEv.pop(0)
class PDraw(Processor):
def InitPersistent(self, *rgprio):
self.rgprio = rgprio
self.msDrawAgain = -1
self.fTimerSet = False
def process(self):
if self.game.ms >= self.msDrawAgain:
for client in self.game.rgclient:
ascr = ansi.Ascr()
for tok in self.game.rgtoken("drawable", self.rgprio):
try:
tok.draw(ascr, client)
except Exception:
print "error drawing"
traceback.print_exc()
client.protocol.Draw(ascr)
self.msDrawAgain = self.game.ms + 120
self.fTimerSet = False
elif not self.fTimerSet:
reactor.callLater((self.msDrawAgain - self.game.ms) / 1000.0, self.game.ensureRun)
self.fTimerSet = True
class Taggable(Ownable):
def InitPersistent(self, owner, *rgtag):
Ownable.InitPersistent(self, owner)
game = owner
while not isinstance(game, Game):
game = game.owner
self.game = game
self.tags = set()
self.tag(*rgtag)
def tag(self, *rgtag):
self.tags |= set(rgtag)
for tag in rgtag:
self.game.tagToken(self, tag)
def untag(self, *rgtag):
self.tags -= set(rgtag)
for tag in rgtag:
self.game.untagToken(self, tag)
def die(self):
for tag in self.tags.copy():
self.untag(tag)
Ownable.die(self)
class Token(Taggable):
def InitPersistent(self, owner, *rgtag):
Taggable.InitPersistent(self, owner, *rgtag)
self.msGamePreWait = 0
self.ms = 0
self.fRunning = True
self.rgtokOwn = TPLS()
def InitTransient(self):
Taggable.InitTransient(self)
self.chEv = stackless.channel()
self.tasklet = stackless.tasklet(self.runI)
self.mpevDgoob = {}
self._fWriteToPersistent = True
self.tasklet()
def __enter__(self):
return self
def __exit__(self, etype, eval, traceback):
self.die()
def wait(self, msDelta):
# have we waited once already this tick? If not, reset
if (self.msGamePreWait != self.game.ms):
self.ms = self.game.ms
msEnd = self.ms + msDelta
delay = (msEnd - self.game.ms) / 1000.0
if delay > 0:
reactor.callLater(delay, self.game.ensureRun)
while (self.game.ms < msEnd):
self.game.evTick.receive(self)
self.ms = msEnd
self.msGamePreWait = self.game.ms
def die(self):
self.tasklet.kill()
self.fRunning = False
Taggable.die(self)
def run(self):
pass
def runI(self):
try:
self.run()
#except TaskletExit:
# raise
except Exception:
print "token script crashed:"
traceback.print_exc()
def FIter(l):
try:
iter(l)
return True
except Exception:
return False
class TokenClient(Token):
def InitPersistent(self, owner, client, *rgtag):
Token.InitPersistent(self, owner, *rgtag)
self.client = client
def FPersist(self):
return False

1
entity.py Normal file
View file

@ -0,0 +1 @@
mpch_entity = [0, 9786, 9787, 9829, 9830, 9827, 9824, 8226, 9688, 9675, 9689, 9794, 9792, 9834, 9835, 9788, 9658, 9668, 8597, 8252, 182, 167, 9644, 8616, 8593, 8595, 8594, 8592, 8735, 8596, 9650, 9660, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 8962, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165, 8359, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171, 187, 9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516, 9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554, 9555, 9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734, 966, 949, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160]

71
haxor.py Normal file
View file

@ -0,0 +1,71 @@
#@+leo-ver=4-thin
#@+node:jpenner.20090526212048.3:@thin haxor.py
from engine import *
from basetoken import *
import telnet
#@<<IntroTerm>>
#@+node:jpenner.20090526212048.6:<<IntroTerm>>
class IntroTerm(Terminal):
#@ @+others
#@+node:jpenner.20090526212048.5:run
def run(self):
self.newLine(3, 300)
self.type("Logon Please: ")
name = self.getLine()
self.newLine(2, 300)
self.typeLn("Welcome, " + name)
self.type("You have ")
self.wait(200)
self.typeLn("top security clearance.")
self.type("You are looking ")
self.wait(200)
self.typeLn("good to-day.")
while True:
self.typeLn("Would you like to download")
self.type("all secret files? [Y/N] ")
if (self.getPrintableKey().upper() == "Y"):
break
self.printSt("No")
self.newLine()
self.typeLn("But thou must!")
self.wait(500)
self.printSt("Yessir!")
self.newLine(2, 50)
self.type("Downloading... ")
spinner = self.newSpinner()
self.wait(3000)
spinner.die()
blnkScrn = Blinker(self.game, self.setColBg, [ansi.RED, ansi.BLUE])
self.newLine(2, 50)
self.typeLn("EXPERT HAX0R DETECTED")
self.typeLn("CODE RED CODE RED")
self.newLine(2, 400)
self.wait(500)
self.typeLn("OH SHIIIIIIIIIIIIIIIIT!")
self.wait(800)
blnkScrn.die()
self.setColBg(ansi.BLACK)
self.newLine(2, 50)
self.printSt("NO CARRIER")
self.newLine()
self.client.quit()
#@-node:jpenner.20090526212048.5:run
#@-others
#@nonl
#@-node:jpenner.20090526212048.6:<<IntroTerm>>
#@nl
class Haxor(object):
def __init__(self):
self.game = GmSimple([AutoJoiner, IntroTerm])
def RunGame(self, client):
client.joinGame(self.game)
def RunServer(self):
telnet.RunServer(self.RunGame)
if __name__ == "__main__":
Haxor().RunServer()
#@nonl
#@-node:jpenner.20090526212048.3:@thin haxor.py
#@-leo

35
login.py Normal file
View file

@ -0,0 +1,35 @@
#@+leo-ver=4-thin
#@+node:jpenner.20090607135901.3:@thin login.py
from basetoken import *
import ansi
class LoginTerm(Terminal):
def run(self):
self.setColBg(ansi.BLUE)
self.newLine(3, 300)
self.type("Logon Please: ")
user = self.getLine()
self.newLine()
self.type("Password: ")
self.chEcho = "*"
passwd = self.getLine()
self.chEcho = None
self.newLine(2, 300)
if self.client.login(user, passwd):
self.typeLn("Welcome to MarMOTS, " + user)
self.typeLn("I see you have driven here in your Ferrari.")
self.typeLn("Logging you in...")
self.wait(250)
self.game.finish(True)
else:
self.setColBg(ansi.RED)
self.typeLn("I am sorry, " + user + ", but you appear to be insufficiently rhinoceros.")
self.typeLn("Please report back after joining the Klik of the Month Klub.")
self.newLine(2,300)
self.setColBg(ansi.BLACK)
self.printSt("NO CARRIER")
self.wait(200)
self.game.finish(False)
#@nonl
#@-node:jpenner.20090607135901.3:@thin login.py
#@-leo

12
marmots_todo.txt Normal file
View file

@ -0,0 +1,12 @@
debugging output:
- decorate classes which we expect not to be in the output, warn if we persist them
-
TRef
Load
Unload (save and close reference)
-- we do not want to hold on to references
-- actually in our case we don't want to save GameWBs at all, we want to persist boards lazily (except for metadata?)
Cldg
-- well, this sucks :P guid? attach to game?

3
runserver.bat Normal file
View file

@ -0,0 +1,3 @@
setup.py build_ext --inplace -c mingw32
whiteboard.py
pause

4
save.sh Normal file
View file

@ -0,0 +1,4 @@
#!/bin/bash
echo save | telnet localhost 20002

33
savecycle.sh Normal file
View file

@ -0,0 +1,33 @@
#!/bin/bash
fnnew="whiteboard.marm.`date "+%F_%H-%M"`"
cd /home/jeremy/marmots
save ()
{
echo save | telnet localhost 20002 &> /dev/null
sleep 5 # wait for save to complete
}
backup ()
{
cp whiteboard.marm $fnnew
gzip $fnnew
}
if [ -e whiteboard.marm ]
then
cp whiteboard.marm whiteboard.marm.old
save
cmp whiteboard.marm whiteboard.marm.old &> /dev/null
if [ $? != 0 ]
then
backup
fi
rm whiteboard.marm.old
else
save
backup
fi

711
scripting.py Normal file
View file

@ -0,0 +1,711 @@
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")

12
setup.py Normal file
View file

@ -0,0 +1,12 @@
#@+leo-ver=4-thin
#@+node:jpenner.20091212133112.13:@thin setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [Extension("ansi_cython", ["ansi_cython.pyx"])]
)
#@-node:jpenner.20091212133112.13:@thin setup.py
#@-leo

233
telnet.py Normal file
View file

@ -0,0 +1,233 @@
#@+leo-ver=4-thin
#@+node:jpenner.20090510085557.10:@thin telnet.py
#@@language python
from twisted.protocols import basic
from twisted.conch import telnet
from twisted.internet.protocol import Factory,ServerFactory
from twisted.internet import protocol, reactor
from zope.interface import implements
from twisted.python import log
import ansi
import engine
import sys
import config
#@<<Server>>
#@+node:jpenner.20090513213413.1:<<Server>>
class AnsiTelnet(protocol.Protocol):
implements(telnet.ITelnetProtocol)
rgoptRemote = [telnet.SGA, telnet.ECHO] #putty sez: 31 (NAWS), 32 (TERMINAL-SPEED), 24 (TERMINAL-TYPE), 39 (NEW-ENVIRON), 36 (ENVIRON), 3(SGA)
# We might support NAWS at some point -- internally we will always deal in 80x25, but it might be helpful to have
# window resizing work, and provide feedback if the window is too small.
# I don't know what we'd do in response to TERMINAL-SPEED, since we're just going to blast out data as fast as possible anyway.
# NEW-ENVIRON might be useful for sending usernames or cookies automatically from flashterm.
# ENVIRON is an older version of NEW-ENVIRON.
# TERMINAL-TYPE is client-to-server only, and the server only speaks ANSI. Again, maybe useful as a feedback mechanism.
rgoptLocal = [telnet.SGA] #putty sez: 1 (ECHO), 3 (SGA)
def __init__(self, client):
print "created"
self.ast = None
self.client = client
self.evKey = None
self.evArrow = None
self.Refresh()
def connectionMade(self):
print "connection made"
rgdefr = []
def AddCb(defr):
"""
rgdefr.append(defr)
def cbWaitForHello(result):
print "cb: ", result, len(rgdefr)
rgdefr.remove(defr)
if len(rgdefr) == 0:
self.Hello()
defr.addCallback(cbWaitForHello)
defr.addErrback(cbWaitForHello)
"""
pass
for opt in self.rgoptRemote:
AddCb(self.transport.will(opt))
for opt in self.rgoptLocal:
AddCb(self.transport.do(opt))
print "end: ", len(rgdefr)
self.Hello()
#@ <<Options>>
#@+node:jpenner.20090514181656.118:<<Options>>
def enableLocal(self, option):
print "enableLocal", ord(option)
return option in self.rgoptLocal
def enableRemote(self, option):
print "enableRemote", ord(option)
return option in self.rgoptRemote
def disableLocal(self, option):
print "disableLocal", option
pass
def disableRemote(self, option):
print "disableRemote", option
pass
#@nonl
#@-node:jpenner.20090514181656.118:<<Options>>
#@nl
def dataReceived(self, data):
if self.ast != None:
data = self.ast + data
ich = 0
ichSplit = 0
fAnsi = False
fEsc = False
for ch in data:
if fAnsi:
if not (ch == ";" or ch.isdigit()):
fAnsi = False
if ch.isalpha():
stRgarg = data[ichSplit + 2:ich]
if len(stRgarg) == 0:
rgarg = []
else:
rgarg = [int(stArg) for stArg in stRgarg.split(";")]
self.RcvAnsi(ch, rgarg)
ichSplit = ich + 1
elif ch == ansi.esc[0]:
fEsc = True
elif fEsc:
fEsc = False
if ch == ansi.esc[1]:
fAnsi = True
if ichSplit < ich - 1:
self.RcvText(data[ichSplit:ich - 1])
ichSplit = ich - 1
ich = ich + 1
if fEsc or fAnsi:
self.ast = data[ichSplit:ich]
else:
self.ast = None
if ichSplit < ich:
self.RcvText(data[ichSplit:ich])
#@ @+others
#@+node:jpenner.20090526105844.6:Hello
def Hello(self):
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)
#@nonl
#@-node:jpenner.20090526105844.6:Hello
#@+node:jpenner.20090526212048.1:Keys
def RcvText(self, text):
if self.client.evKey:
for ch in text:
self.client.evKey.fire(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])
else:
print "unrecognized code", code, rgarg
def CreateEvents(self, client, game):
client.evKey = engine.Event(game)
#@nonl
#@-node:jpenner.20090526212048.1:Keys
#@+node:jpenner.20090527144214.1:Draw
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?
self.ascr = ascr
def Refresh(self):
self.ascr = ansi.Ascr(config.W, config.H, ansi.achInvd)
#@nonl
#@-node:jpenner.20090527144214.1:Draw
#@+node:jpenner.20090529173104.4:connectionLost
def connectionLost(self, reason):
print "lost connection"
self.client.removeDgQuit(self.transport.loseConnection)
self.client.quit()
#@nonl
#@-node:jpenner.20090529173104.4:connectionLost
#@-others
#@nonl
#@-node:jpenner.20090513213413.1:<<Server>>
#@nl
#@<<factory>>
#@+node:jpenner.20090515161650.1:<<factory>>
class AnsiFactory(ServerFactory):
def __init__(self, fnRun):
self.fnRun = fnRun
def buildProtocol(self, addr):
p = telnet.TelnetTransport(AnsiTelnet, engine.Client())
p.factory = self
print "built protocol for ", addr
return p
#@-node:jpenner.20090515161650.1:<<factory>>
#@nl
#@<<Flash Policy>>
#@+node:jpenner.20090518103251.118:<<Flash Policy>>
class FlashPolicy(basic.LineReceiver):
delimiter = '\0'
def lineReceived(self,line):
if line == "<policy-file-request/>":
self.sendLine("<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + str(config.PORT_TELNET) + "\" /></cross-domain-policy>")
#@-node:jpenner.20090518103251.118:<<Flash Policy>>
#@nl
#@<<Command server>>
#@+node:jpenner.20090914034457.2:<<Command server>>
class CmdProtocol(basic.LineReceiver):
def connectionMade(self):
if self.transport.getHost().host != "127.0.0.1":
self.transport.write("Sorry, you must connect from localhost")
self.transport.loseConnection()
def lineReceived(self, line):
self.transport.write(self.factory.fnCmd(line) + self.delimiter)
class CmdFactory(ServerFactory):
def __init__(self, fnCmd):
self.fnCmd = fnCmd
def buildProtocol(self, addr):
p = CmdProtocol()
p.factory = self
print "built cmd protocol for ", addr
return p
#@-node:jpenner.20090914034457.2:<<Command server>>
#@nl
#@<<runner>>
#@+node:jpenner.20090513213413.2:<<runner>>
def RunServer(fnRun):
log.startLogging(sys.stdout)
factoryPolicy = Factory()
factoryPolicy.protocol = FlashPolicy
reactor.listenTCP(config.PORT_TELNET, AnsiFactory(fnRun), 50, config.BIND_HOSTNAME)
if config.PORT_FLASHPOLICY:
reactor.listenTCP(config.PORT_FLASHPOLICY, factoryPolicy, 50, config.BIND_HOSTNAME)
reactor.run()
def RunCmdServer(fnCmd):
if config.PORT_CMDSERVER:
reactor.listenTCP(config.PORT_CMDSERVER, CmdFactory(fnCmd), 50, "localhost")
#@nonl
#@-node:jpenner.20090513213413.2:<<runner>>
#@nl
#@-node:jpenner.20090510085557.10:@thin telnet.py
#@-leo

8
testsig.py Normal file
View file

@ -0,0 +1,8 @@
import signal
def handler(signum, frame):
print "signal:", signum, frame
signal.signal(signal.SIGINT, handler)
input()

268
tpers.py Normal file
View file

@ -0,0 +1,268 @@
import cPickle
import pdb
import traceback
def Decorator(dg):
def DecoratorNew(*rgarg, **mparg):
def CallDecorator(o):
return dg(o, *rgarg, **mparg) or o
return CallDecorator
return DecoratorNew
@Decorator
def Version(cls, vr):
cls._version = vr
def RenameFrom(stName, namespace):
def SetOldName(cls):
namespace[stName] = cls
return cls
return SetOldName
class TransientSetter(object):
def __init__(self, obj):
self.obj = obj
try:
self._fWriteOld = obj._fWriteToPersistent
except Exception:
self._fWriteOld = True
def __enter__(self):
self.obj._fWriteToPersistent = False
return self.obj
def __exit__(self, type, value, traceback):
self.obj._fWriteToPersistent = self._fWriteOld
@Version(1)
class TPrs(object):
def __init__(self, *rgarg, **mparg):
self._persistent = TPM()
self._fWriteToPersistent = True
self._versionCurr = self._version
self._fPersistent = True
self.InitPersistent(*rgarg, **mparg)
with self.SetTransiently():
self.InitTransient()
def InitPersistent(self, *rgarg, **mparg):
pass
def InitTransient(self):
pass
def SetTransiently(self):
return TransientSetter(self)
def MakeTransient(self, key, value):
try:
del self._persistent[key]
except Exception:
pass
with self.SetTransiently():
setattr(self, key, value)
def FPersist(self):
return self._fPersistent
def DontPersist(self):
self._fPersistent = False
def UpgradeFrom(self, versionOld):
pass
def __getattr__(self, key):
stPersistent = "no persistent yet"
if key != "_persistent":
try:
return self._persistent[key]
except Exception:
stPersistent = str(self._persistent)
raise AttributeError("Attribute '" + key + "' not found in object with type '" + type(self).__name__ + "':" + stPersistent + " __dict__:" + str(self.__dict__))
__obj_setattr = object.__setattr__
__obj_delattr = object.__delattr__
def __setattr__(self, key, value):
try:
if self._fWriteToPersistent or key in self._persistent:
self._persistent[key] = value
try:
self.__obj_delattr(key)
except AttributeError:
pass
return
except Exception: pass
self.__obj_setattr(key, value)
def __delattr__(self, key):
try:
del self._persistent[key]
return
except Exception: pass
self.__obj_delattr(key)
def __reduce__(self):
if self.FPersist():
return (NewObjWithClass, (type(self),), self._persistent)
else:
return (NewObjWithClass, (None,))
def __setstate__(self, state):
self._persistent = state
self._fWriteToPersistent = True
if self._versionCurr != self._version:
Odb.rgtprsToUpgrade.append(self)
with self.SetTransiently():
self.InitTransient()
def _Upgrade(self):
self.UpgradeFrom(self._versionCurr)
self._versionCurr = self._version
class Odb(object):
@staticmethod
def Save(tprs, fn):
with open(fn, "w") as fl:
cPickle.dump(tprs, fl)
@classmethod
def Load(cls, fn):
cls.rgtprsToUpgrade = []
try:
with open(fn, "r") as fl:
tprs = cPickle.load(fl)
except Exception as e:
print "error unpickling:", e
traceback.print_exc()
return None
if len(cls.rgtprsToUpgrade) > 0:
for tprsToUpgrade in cls.rgtprsToUpgrade:
tprsToUpgrade._Upgrade()
fnUpgraded = fn + ".upgraded"
Odb.Save(tprs, fnUpgraded)
tprs = Odb.Load(fnUpgraded)
cls.rgtprsToUpgrade = None
return tprs
clsList = list
clsDict = dict
clsSet = set
clsTuple = tuple
def MkTransparent(value):
if type(value) == list:
return TPL(value)
elif type(value) == dict:
return TPM(value)
elif type(value) == set:
return TPS(value)
elif type(value) == tuple:
return TPT(value)
else:
return value
def RgTransparent(rg):
if rg == None: return []
return [MkTransparent(x) for x in rg]
def MpTransparent(mp):
if isinstance(mp, TPM): return mp
mpNew = {}
if mp != None:
for k,v in mp.iteritems():
mpNew[k] = MkTransparent(v)
return mpNew
def FPersist(obj):
return (not isinstance(obj, TPrs)) or obj.FPersist()
def MkPersistable(obj):
if FPersist(obj):
return obj
return None
def NewObjWithClass(cls):
if cls == None:
return None
return cls.__new__(cls)
class TPL(clsList):
__pl_setitem = clsList.__setitem__
__pl_setslice = clsList.__setslice__
__pl_iadd = clsList.__iadd__
__pl_append = clsList.append
__pl_insert = clsList.insert
__pl_extend = clsList.extend
def __init__(self, rg = None):
clsList.__init__(self, RgTransparent(rg))
def __setitem__(self, i, item):
return self.__pl_setitem(i, MkTransparent(item))
def __setslice__(self, i, j, other):
return self.__pl_setslice(i, j, RgTransparent(other))
def __iadd__(self, other):
return self.__pl_iadd(RgTransparent(other))
def append(self, item):
return self.__pl_append(MkTransparent(item))
def insert(self, i, item):
return self.__pl_insert(i, MkTransparent(item))
def extend(self, other):
return self.__pl_extend(RgTransparent(other))
def __reduce__(self):
return (MkTransparent, ([MkPersistable(x) for x in self],))
# Strip weak references rather than replacing them with None
class TPLS(TPL):
def __reduce__(self):
return (MkTransparent, ([x for x in self if FPersist(x)],))
class TPM(clsDict):
__pm_setitem = clsDict.__setitem__
__pm_update = clsDict.update
def __init__(self, *rgarg, **kwarg):
clsDict.__init__(self, MpTransparent(dict(*rgarg, **kwarg)))
def __setitem__(self, k, v):
return self.__pm_setitem(k, MkTransparent(v))
def update(self, other, **kwargs):
return self.__pm_update(MpTransparent(other), **MpTransparent(kwargs))
def __reduce__(self):
mp = {}
for k, v in self.iteritems():
if FPersist(k):
mp[k] = MkPersistable(v)
return (MkTransparent, (mp,))
class TPS(clsSet):
__ps_update = clsSet.update
__ps_ior = clsSet.__ior__
__ps_add = clsSet.add
def __init__(self, rg = None):
clsSet.__init__(self, RgTransparent(rg))
def update(self, *rgother):
return self.__ps_update(*RgTransparent(rgother))
def __ior__(self, other):
return self.__ps_ior(MkTransparent(other))
def add(self, elem):
return self.__ps_add(MkTransparent(elem))
def __reduce__(self):
return (MkTransparent, (set([x for x in self if FPersist(x)]),))
class TPT(clsTuple):
def __new__(cls, tup = None):
return clsTuple.__new__(cls, RgTransparent(tup))
def __reduce__(self):
return (MkTransparent, (tuple([MkPersistable(x) for x in self]),))

103
tpers_old.py Normal file
View file

@ -0,0 +1,103 @@
#@+leo-ver=4-thin
#@+node:jpenner.20090714203921.6:@thin tpers_old.py
import ZODB
import persistent
#@+others
#@+node:jpenner.20090714203921.7:def MkTransparent
def MkTransparent(value):
if type(value) == list:
return TPL(value)
elif type(value) == dict:
return TPM(value)
elif type(value) == set:
return TPS(value)
elif type(value) == tuple:
return TPT(value)
else:
return value
#@-node:jpenner.20090714203921.7:def MkTransparent
#@+node:jpenner.20090714203921.10:def RgTransparent
def RgTransparent(rg):
if rg == None: return []
return [MkTransparent(x) for x in rg]
#@-node:jpenner.20090714203921.10:def RgTransparent
#@+node:jpenner.20090714203921.11:def MpTransparent
def MpTransparent(mp):
if isinstance(mp, TPM): return mp
mpNew = {}
if mp != None:
for k,v in mp.iteritems():
mpNew[k] = MkTransparent(v)
return mpNew
#@-node:jpenner.20090714203921.11:def MpTransparent
#@+node:jpenner.20090714203921.8:class TPrs
class TPrs(persistent.Persistent):
__prs_setattr = persistent.Persistent.__setattr__
def __setattr__(self, name, value):
self.__prs_setattr(name, MkTransparent(value))
#@-node:jpenner.20090714203921.8:class TPrs
#@+node:jpenner.20090714203921.9:class TPL
class TPL(clsList):
__pl_setitem = clsList.__setitem__
__pl_setslice = clsList.__setslice__
__pl_iadd = clsList.__iadd__
__pl_append = clsList.append
__pl_insert = clsList.insert
__pl_extend = clsList.extend
def __init__(self, rg = None):
clsList.__init__(self, RgTransparent(rg))
def __setitem__(self, i, item):
return self.__pl_setitem(i, MkTransparent(item))
def __setslice__(self, i, j, other):
return self.__pl_setslice(i, j, RgTransparent(other))
def __iadd__(self, other):
return self.__pl_iadd(RgTransparent(other))
def append(self, item):
return self.__pl_append(MkTransparent(item))
def insert(self, i, item):
return self.__pl_insert(i, MkTransparent(item))
def extend(self, other):
return self.__pl_extend(RgTransparent(other))
def __reduce__(self):
return (MkTransparent, ([MkPersistable(x) for x in self],))
# Strip weak references rather than replacing them with None
class TPLS(TPL):
def __reduce__(self):
return (MkTransparent, ([x for x in self if FPersist(x)],))
#@-node:jpenner.20090714203921.9:class TPL
#@+node:jpenner.20090714203921.12:class TPM
class TPM(clsDict):
__pm_setitem = clsDict.__setitem__
__pm_update = clsDict.update
def __init__(self, *rgarg, **kwarg):
clsDict.__init__(self, MpTransparent(dict(*rgarg, **kwarg)))
def __setitem__(self, k, v):
return self.__pm_setitem(k, MkTransparent(v))
def update(self, other, **kwargs):
return self.__pm_update(MpTransparent(other), **MpTransparent(kwargs))
def __reduce__(self):
mp = {}
for k, v in self.iteritems():
if FPersist(k):
mp[k] = MkPersistable(v)
return (MkTransparent, (mp,))
#@-node:jpenner.20090714203921.12:class TPM
#@-others
#@-node:jpenner.20090714203921.6:@thin tpers_old.py
#@-leo

127
util.py Normal file
View file

@ -0,0 +1,127 @@
from tpers import TPrs
import ansi
# probably reinventing the wheel :/
class Rgseq(TPrs):
def InitPersistent(self, *rgseq):
self.rgseq = rgseq
def __len__(self):
return sum([len(seq) for seq in self.rgseq])
def __getitem__(self, i):
c = 0
for seq in self.rgseq:
cSeq = len(seq)
if i < c + cSeq:
return seq[i - c]
c = c + cSeq
raise IndexError
def index(self, o):
c = 0
for seq in self.rgseq:
try:
iSeq = seq.index(o)
return iSeq + c
except ValueError:
c = c + len(seq)
raise ValueError
class Snippet(object):
def __init__(self, st, ichStart, ichLim):
self.st = st
self.ichStart = ichStart
self.ichLim = ichLim
def RgstWrapped(st, w, fForEditing = False, dxStart = 0):
return [snippet.st for snippet in RgSnippetWrapped(st, w, fForEditing, dxStart)]
def RgSnippetWrapped(st, w, fForEditing = False, xStart = 0):
ichWrap = -1
ichStart = 0
for ich, ch in enumerate(st):
if not fForEditing and ch == ' ':
ichWrap = ich
if ich == ichStart + w - xStart:
ichStartNew = ichWrap + 1
if ichWrap < 0:
ichWrap = ich
ichStartNew = ich
elif fForEditing: # don't swallow spaces
ichWrap = ichStartNew
yield Snippet(st[ichStart:ichWrap], ichStart, ichStartNew)
ichStart = ichStartNew
ichWrap = -1
xStart = 0
if fForEditing and ch == ' ':
ichWrap = ich
if ichStart < len(st) or ichStart == 0:
yield Snippet(st[ichStart:], ichStart, len(st))
# selection helpers
def IoInc(rgo, io, fnSelectable, fRebound = True):
io = io + 1
while io < len(rgo) and not fnSelectable(rgo[io]):
io = io + 1
if io >= len(rgo) or not fnSelectable(rgo[io]):
if fRebound:
return IoDec(rgo, io, fnSelectable, False)
return -1
return io
def IoDec(rgo, io, fnSelectable, fRebound = True):
io = io - 1
while io > 0 and not fnSelectable(rgo[io]):
io = io - 1
if io < 0 or not fnSelectable(rgo[io]):
if fRebound:
return IoInc(rgo, io, fnSelectable, False)
return -1
return io
class Stedit(TPrs):
def InitPersistent(self, dgEnter = None, stInitial = ""):
self.dgEnter = dgEnter
self.SetValue(stInitial)
def SetValue(self, st):
self.st = st
self.ich = len(st)
def GetValue(self):
return self.st
def StForSize(self, fSel = True):
if fSel and self.ich == len(self.st):
return self.st + "_"
return self.st
def HandleKey(self, key):
if key == ansi.K_LEFT and self.ich > 0:
self.ich = self.ich - 1
elif key == ansi.K_RIGHT and self.ich < len(self.st):
self.ich = self.ich + 1
elif key == ansi.K_BACKSPACE and self.ich > 0:
self.st = self.st[:self.ich - 1] + self.st[self.ich:]
self.ich = self.ich - 1
elif key == ansi.K_DEL and self.ich < len(self.st):
self.st = self.st[:self.ich] + self.st[self.ich + 1:]
elif key == ansi.K_HOME:
self.ich = 0
elif key == ansi.K_END:
self.ich = len(self.st)
elif ansi.FKeyPrintable(key):
self.st = self.st[:self.ich] + key + self.st[self.ich:]
self.ich = self.ich + 1
elif ansi.FEnter(key) and self.dgEnter != None:
if not self.dgEnter(self.st):
self.st = ""
self.ich = 0
else:
return False
return True
def DrawCursor(self, ascr, x, y, colFg, colBg, snippet):
if self.ich >= snippet.ichStart and (snippet.ichLim < 0 or self.ich < snippet.ichLim):
if self.ich == len(self.st):
ch = ' '
else:
ch = self.st[self.ich]
ascr.PutAch(ansi.MkAch(ch, colFg, colBg), x + self.ich - snippet.ichStart, y)

678
whiteboard.py Normal file
View file

@ -0,0 +1,678 @@
#@+leo-ver=4-thin
#@+node:jpenner.20090528201601.6:@thin whiteboard.py
from engine import *
from basetoken import *
from tpers import *
from datetime import *
from util import *
import telnet
import time
import login
import weakref
#@<<Whiteboard>>
#@+node:jpenner.20090528201601.9:<<Whiteboard>>
class Layer(TPrs):
def InitPersistent(self, ascr, stName):
self.ascr = ascr
self.stName = stName
def StName(self):
return self.stName
def SetName(self, st):
self.stName = st
def Draw(self, ascr):
ascr.PutAscr(self.ascr)
def FSelectable(self):
return True
@Version(3)
class Board(Ownable):
def InitPersistent(self, owner, stName, user, rglayer=None, dtLastModified=None):
Ownable.InitPersistent(self, owner)
if rglayer == None:
rglayer = [Layer(ansi.Ascr(self.W(), self.H()), "Layer 1")]
self.rglayer = rglayer
self.stName = stName
self.user = user
self.chat = Chat()
if dtLastModified == None:
self.SetTimestamp()
else:
self.dtLastModified = dtLastModified
def StName(self):
return self.owner.StNameBoard(self)
def StLastModified(self):
return self.dtLastModified.strftime("%b %d, %Y at %I:%M%p")
def LayerByName(self, stName):
for layer in self.rglayer:
if layer.StName().lower() == stName.lower():
return layer
return None
def NewLayer(self, stName):
if len(self.rglayer) < 8:
layerNew = Layer(ansi.Ascr(self.W(), self.H()), stName)
self.rglayer.append(layerNew)
return layerNew
def MoveLayer(self, layer, fUp):
ilayer = self.rglayer.index(layer)
if fUp and ilayer > 0:
ilayer = ilayer - 1
elif not fUp and ilayer < len(self.rglayer) - 1:
ilayer = ilayer + 1
self.rglayer.remove(layer)
self.rglayer.insert(ilayer, layer)
def W(self): return config.W
def H(self): return config.H
def Touch(self):
self.SetTimestamp()
self.owner.BoardTouched(self)
def SetTimestamp(self):
self.dtLastModified = datetime.now()
def draw(self, ascr):
for layer in reversed(self.rglayer):
layer.Draw(ascr)
#@ @+others
#@+node:jpenner.20090602154503.5:Save
def Save(self):
fn = config.DIR_ANSI + "/" + "_".join([str(x) for x in time.localtime()])
ascr = ansi.Ascr(self.W(), self.H())
self.draw(ascr)
with open(fn + ".html", "w") as fl:
fl.write("<html><body bgcolor='#000000'><center>")
fl.write(ascr.Hst())
fl.write("</center></body></html>")
with open(fn + ".ans", "w") as fl:
fl.write(ascr.Ast())
#@nonl
#@-node:jpenner.20090602154503.5:Save
#@-others
def UpgradeFrom(self, versionOld):
if versionOld < 2:
gameWB = [gameWB for gameWB in self.owner.rggameWB if gameWB.rgtoken("whiteboard")[0].board == self][0]
self.stName = gameWB.stName
self.user = gameWB.user
if versionOld < 3:
self.chat = Chat()
@Version(5)
class Whiteboard(Token):
def InitPersistent(self, game, board):
Token.InitPersistent(self, game, "whiteboard")
self.board = board
def UpgradeFrom(self, versionOld):
if versionOld < 3:
dt = None
else:
dt = self.dtLastModified
del self.dtLastModified
if versionOld < 4:
rglayer = [Layer(self.ascr, "Layer 1")]
del self.ascr
self.untag("drawable")
self.untag("solid")
else:
rglayer = self.rglayer
del self.rglayer
if versionOld < 5:
self.board = Board(self.game.gameLobby, self.game.stName, self.game.user, rglayer, dt)
#@-node:jpenner.20090528201601.9:<<Whiteboard>>
#@nl
#@<<Chat>>
#@+node:jpenner.20090918200439.1:<<Chat>>
class Chl(object):
def __init__(self, client, st):
self.user = client.cld.user
self.st = st.rstrip()
class ChlMsg(Chl):
def StUser(self):
return "<" + self.user + ">"
def Col(self):
return ansi.WHITE
class ChlAct(Chl):
def StUser(self):
return "* " + self.user
def Col(self):
return ansi.MAGENTA
class ChlSys(Chl):
def StUser(self):
return self.user
def Col(self):
return ansi.BLUE
class Chat(TPrs):
def InitTransient(self):
TPrs.InitTransient(self)
self.cchl = 100
self.DetachFromGame()
def InitPersistent(self):
TPrs.InitPersistent(self)
self.rgchl = []
def AttachToGame(self, game):
self.game = game
self.evChat = Event(game)
def DetachFromGame(self):
self.game = None
self.evChat = None
def Add(self, chl):
if len(chl.st) > 0:
self.rgchl.insert(0, chl)
if len(self.rgchl) > self.cchl:
self.rgchl = self.rgchl[:self.cchl]
self.evChat.fire(chl)
def CChl(self):
return len(self.rgchl)
def CUsers(self):
return len(self.game.rgclient)
def DrawMsg(self, ascr, x, y, w, h, colBg=ansi.BLACK, ichl=0):
yDraw = y + h - 1
for chl in self.rgchl[ichl:]:
stUser = chl.StUser()
colFg = chl.Col()
wMsg = w - len(stUser) - 1
rgstMsg = RgstWrapped(chl.st, wMsg)
rgstMsg.reverse()
for istMsg, stMsg in enumerate(rgstMsg):
if istMsg == len(rgstMsg) - 1:
st = "{0} {1:{2}}".format(stUser, stMsg, wMsg)
else:
st = "{0:{1}} {2:{3}}".format("", len(stUser), stMsg, wMsg)
ascr.PutSt(st, x, yDraw, colFg, colBg)
yDraw = yDraw - 1
if yDraw == y - 1:
return
while yDraw >= y:
ascr.PutSt("{0:{1}}".format("", w), x, yDraw, ansi.WHITE, colBg)
yDraw = yDraw - 1
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)
yDraw = yDraw + 1
if yDraw == y + h:
break
while yDraw < y + h:
ascr.PutSt("{0:{1}}".format("", w), x, yDraw, ansi.WHITE, colBg)
yDraw = yDraw + 1
#@-node:jpenner.20090918200439.1:<<Chat>>
#@nl
#@<<Cursor>>
#@+node:jpenner.20090528201601.10:<<Cursor>>
class Cursor(TokenClient):
def InitPersistent(self, game, client):
TokenClient.InitPersistent(self, game, client, "drawable", "cursor")
self.fBlink = False
self.cDontBlink = 0
self.whiteboard = self.game.rgtoken("whiteboard")[0].board
self.pos = ansi.Pos(self.whiteboard.W(), self.whiteboard.H())
miFg = MiColour("Foreground", ansi.rgcolorFg, ansi.WHITE)
miBg = MiColour("Background", ansi.rgcolorBg, ansi.BLACK)
miChars = MiChars([[49, 50, 51, 52, 53, 54, 55, 56, 57, 48], #digits
[176, 177, 178, 219, 223, 220, 221, 222, 254, 249], #blocks
[218, 191, 192, 217, 196, 179, 195, 180, 193, 194], #single lines
[201, 187, 200, 188, 205, 186, 204, 185, 202, 203], #double lines
[213, 184, 212, 190, 205, 179, 198, 181, 207, 209], #sing vert, doub horiz
[214, 183, 211, 189, 196, 186, 199, 182, 208, 210], #doub vert, sing horiz
[197, 206, 216, 215, 173, 168, 169, 170, 174, 175], #crosses
#[ 1, 2, 3, 4, 5, 6, 14, 15, 19, 20], #smiles
[224, 225, 226, 227, 228, 229, 230, 231, 232, 233], #greek
[234, 235, 236, 237, 238, 239, 240, 241, 242, 243], #crap
[244, 245, 246, 247, 248, 249, 251, 252, 253, 167], #more crap
[155, 156, 157, 158, 159, 171, 172, 166, 32, 32], #$
[142, 132, 131, 143, 134, 133, 160, 145, 146, 32], #a
[128, 135, 137, 136, 138, 144, 130, 164, 165, 32], #c, e, n
[139, 140, 141, 161, 153, 148, 147, 149, 162, 32], #i, o
[154, 129, 150, 151, 163, 32, 32, 32, 32, 32], #u
], miFg, miBg)
miQuit = MiButton("Back to Menu", self.client.leaveGame)
self.cf = MiMenu([None, miFg, miBg, None, miChars, None, MiButton("Save", self.Save), None, miQuit, None])
self.miChat = MiMenu([None, MiChat(client, 13, self.whiteboard.chat), MiTypein(self.SendMsg), None, miQuit, None])
self.rgmiLayer = RgmiProjected(self.whiteboard.rglayer, DgProjectMiButton(self.SelectLayer))
self.miLayers = 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]))
self.ovPopup = OvPopup(self, self.client, MiTab.MiTabbed(["Drawing", self.cf], ["Layers", self.miLayers], ["Chat", self.miChat]))
miStatus = MiMenuHoriz([MiStatic("Hit <Tab> for menu"), MiValue(miChars)])
miStatus.ListenForNotice(self.miChat)
self.ovStatus = OvStatic(self, self.client, miStatus, OvStatic.BOTTOM)
self.SelectLayer(self.whiteboard.rglayer[0])
WhiteboardDraw(self, client)
def Save(self):
self.whiteboard.Save()
msgscroller = self.game.rgtoken("msgscroller")[0]
msgscroller.evPost.fire("Saved picture")
def SelectLayer(self, layer):
self.ovPopup.SetSelection("layer", self.rgmiLayer.MiFromValue(layer))
miRename = self.miLayers.MiByName("LayerName").SetValue(layer.StName())
return True
def GetLayer(self):
return self.ovPopup.GetSelection("layer").Value()
def NewLayer(self):
ilayer = 1
stLayer = None
while stLayer == None:
stLayer = "Layer " + str(ilayer)
if self.whiteboard.LayerByName(stLayer) != None:
stLayer = None
ilayer = ilayer + 1
layerNew = self.whiteboard.NewLayer(stLayer)
if layerNew != None:
self.SelectLayer(layerNew)
return True
def LayerUp(self):
self.whiteboard.MoveLayer(self.GetLayer(), True)
return True
def LayerDown(self):
self.whiteboard.MoveLayer(self.GetLayer(), False)
return True
def RenameLayer(self, st):
if st != "":
self.GetLayer().SetName(st)
return True
def blinkCursor(self, fBlink):
self.fBlink = fBlink
if not fBlink and self.cDontBlink > 0:
self.cDontBlink = self.cDontBlink - 1
def SendMsg(self, st):
if st.lower().startswith("/me ") and len(st.rstrip()) > 3:
self.whiteboard.chat.Add(ChlAct(self.client, st[4:]))
else:
self.whiteboard.chat.Add(ChlMsg(self.client, st))
def OnChat(self, chl):
if type(chl) != ChlSys:
self.miChat.FlagNotice()
def run(self):
with self.whiteboard.chat.evChat.oob(self, self.OnChat):
while True:
key = self.client.evKey.receive(self)
fDontBlink = True
if key == ansi.K_LEFT:
self.pos.Left()
elif key == ansi.K_RIGHT:
self.pos.Right()
elif key == ansi.K_UP:
self.pos.Up()
elif key == ansi.K_DOWN:
self.pos.Down()
elif key == ansi.K_BACKSPACE:
self.pos.Left()
self.PutWb(ansi.achBlank)
elif key == ansi.K_DEL:
self.PutWb(ansi.achBlank)
self.pos.Right()
elif key == ansi.K_TAB:
fDontBlink = False
self.ovPopup.evShow.fire()
self.ovPopup.evDone.receive(self)
elif key == ansi.K_HOME:
self.Skip(self.pos.Left)
elif key == ansi.K_END:
self.Skip(self.pos.Right)
elif key == ansi.K_PGUP:
self.Skip(self.pos.Up)
elif key == ansi.K_PGDN:
self.Skip(self.pos.Down)
elif ansi.FKeyPrintable(key):
if key.isdigit():
self.PutWb(chr(self.cf.Value("Characters")[IchFromCh(key)]))
else:
self.PutWb(key)
self.pos.Right()
else:
print "weird key:", ansi.StrKey(key)
fDontBlink = False
if fDontBlink:
self.cDontBlink = 2 if self.fBlink else 1
if self.pos.Y() < self.whiteboard.H() / 2:
self.ovStatus.kplace = OvStatic.BOTTOM
else:
self.ovStatus.kplace = OvStatic.TOP
def PutWb(self, ch):
self.Put(ch, self.GetLayer().ascr)
self.whiteboard.Touch()
def Put(self, ch, ascr):
if type(ch) == str:
ach = ansi.MkAch(ch, self.cf.Value("Foreground"), self.cf.Value("Background"))
else:
ach = ch
ascr.PutAch(ach, self.pos.X(), self.pos.Y())
def GetAch(self):
return self.GetLayer().ascr.GetAch(self.pos.X(), self.pos.Y())
def Skip(self, dgMove):
self.SkipI(dgMove, self.GetAch())
def SkipI(self, dgMove, ach):
fStop = False
while not fStop:
fStop = not dgMove() or self.GetAch() != ach
def draw(self, ascr, client):
if self.fBlink or self.cDontBlink > 0:
if client == self.client:
chCursor = chr(176)
ach = ascr.GetAch(self.pos.X(), self.pos.Y())
if ach != None and ansi.ChFromAch(ach) == chCursor:
chCursor = chr(177)
self.Put(chCursor, ascr)
elif self.fBlink:
self.Put(str(self.client.Cldg().iclient)[0], ascr)
class WhiteboardDraw(TokenClient):
def InitPersistent(self, owner, client):
TokenClient.InitPersistent(self, owner, client, "drawable", "solid")
def draw(self, ascr, client):
if client == self.client:
if self.owner.miLayers.Value("Show One"):
self.owner.GetLayer().Draw(ascr)
else:
self.owner.whiteboard.draw(ascr)
class CursorBlinker(Token):
def InitPersistent(self, owner):
Token.InitPersistent(self, owner)
Blinker(self, self.BlinkAllCursors)
def BlinkAllCursors(self, fBlink):
for tok in self.game.rgtoken("cursor"):
tok.blinkCursor(fBlink)
#@-node:jpenner.20090528201601.10:<<Cursor>>
#@nl
#@<<Overlay>>
#@+node:jpenner.20090614150414.1:<<Overlay>>
#@+others
#@+node:jpenner.20090529173104.19:MiColour
class MiColour(MiList):
def InitPersistent(self, stName, rgcolor, col):
self.rgcolor = rgcolor
MiList.InitPersistent(self, rgcolor, rgcolor.index(col))
self.stName = stName
def StName(self):
return self.stName
def DrawValue(self, ascr, x, y, selor):
for icol in range(len(self.rgcolor)):
col = self.rgcolor[icol]
ascr.PutAch(ansi.MkAch(chr(219) if icol != self.ival else chr(254), col, ansi.BLACK if col != ansi.BLACK else ansi.WHITE), x + icol, y)
#@-node:jpenner.20090529173104.19:MiColour
#@+node:jpenner.20090529173104.20:MiChars
class MiChars(MiList):
def InitPersistent(self, rgchar, miFg, miBg):
MiList.InitPersistent(self, rgchar)
self.miFg = miFg
self.miBg = miBg
def StName(self):
return "Characters"
def DrawValue(self, ascr, x, y, selor):
for ich, ch in enumerate(self.Value()):
ascr.PutSt(ChFromIch(ich) + ":", x, y, self.ColFg(), self.ColBg(selor))
ascr.PutAch(ansi.MkAch(chr(ch), self.miFg.Value(), self.miBg.Value()), x + 2, y)
x = x + 4
def ChFromIch(ich):
if ich == 9:
return '0'
return str(ich + 1)
def IchFromCh(ch):
if ch == '0':
return 9
return int(ch) - 1
#@nonl
#@-node:jpenner.20090529173104.20:MiChars
#@+node:jpenner.20090926091308.1:MiChat
class MiChat(Mi):
KWNDMSG = 0
KWNDUSERS = 1
def InitPersistent(self, client, height, chat):
Mi.InitPersistent(self)
self.client = client
self.chat = chat
self.height = height
assert height > 2
self.kwnd = self.KWNDMSG
self.imsg = 0
self.iuser = 0
def StName(self):
return "Chat"
def HandleKey(self, key):
if self.kwnd == self.KWNDUSERS:
if key == ansi.K_LEFT:
self.kwnd = self.KWNDMSG
elif (key == 'a' or key == 'A') and self.iuser > 0:
self.iuser = self.iuser - 1
elif (key == 'z' or key == 'Z') and self.iuser < self.chat.CUsers() - 1:
self.iuser = self.iuser + 1
else:
return False
else: #KWNDMSG
if key == ansi.K_RIGHT:
self.kwnd = self.KWNDUSERS
elif (key == 'a' or key == 'A') and self.imsg < self.chat.CChl() - 1:
self.imsg = self.imsg + 1
elif (key == 'z' or key == 'Z') and self.imsg > 0:
self.imsg = self.imsg - 1
else:
return False
return True
def Height(self, w):
return self.height
def ColBgDefault(self):
return ansi.BLACK
def ColBgSelected(self, fPri):
return ansi.BLACK
def ColFg(self):
return ansi.WHITE
def FIgnoreParent(self):
return True
def Draw(self, ascr, x, y, w, selor):
wChat = (w / 4) * 3
wUser = (w / 4) - 1
self.chat.DrawMsg(ascr, x, y, wChat, self.height - 1, self.ColBg(selor), self.imsg)
for yT in range(y, y + self.height - 1):
ascr.PutAch(ansi.MkAch(chr(179)), x + wChat, yT)
ascr.PutSt("{0:{1}<{2}}{3}{0:{1}<{4}}".format("", chr(196), wChat, chr(193), wUser), x, y + self.height - 1)
self.chat.DrawUsers(ascr, x + wChat + 1, y, wUser, self.height - 1, self.ColBg(selor), self.iuser)
if selor.KSel() == Selor.PRI:
if self.kwnd == self.KWNDMSG:
xBar = x + wChat - 1
pct = 1 - (self.imsg / float(self.chat.CChl()))
else: # KWNDUSERS
xBar = x + w - 1
pct = self.iuser / float(self.chat.CUsers())
yBar = int(y + (pct * (self.height - 4)))
ascr.PutAch(ansi.MkAch("A", ansi.RED, ansi.WHITE), xBar, yBar)
ascr.PutAch(ansi.MkAch(chr(186), ansi.RED, ansi.WHITE), xBar, yBar + 1)
ascr.PutAch(ansi.MkAch("Z", ansi.RED, ansi.WHITE), xBar, yBar + 2)
#@-node:jpenner.20090926091308.1:MiChat
#@-others
#@nonl
#@-node:jpenner.20090614150414.1:<<Overlay>>
#@nl
#@<<Joiner>>
#@+node:jpenner.20090529173104.3:<<Joiner>>
class Joiner(Token):
def InitPersistent(self, owner):
Token.InitPersistent(self, owner)
self.msgScroller = self.game.rgtoken("msgscroller")[0]
self.board = self.game.rgtoken("whiteboard")[0].board
def OnJoin(self, client):
with client.Cldg().SetTransiently() as cldg:
cldg.iclient = -1
iclient = 1
rgiclient = [clientT.Cldg().iclient for clientT in self.game.rgclient]
while iclient in rgiclient:
iclient = iclient + 1
cldg.iclient = iclient
self.msgScroller.evPost.fire(client.cld.user + "(#" + str(cldg.iclient) + ") has joined! :)")
self.board.chat.Add(ChlSys(client, "has joined"))
def OnLeave(self, client):
self.msgScroller.evPost.fire(client.cld.user + " has left! :(")
self.board.chat.Add(ChlSys(client, "has left"))
def run(self):
while True:
with self.game.evJoin.oob(self, self.OnJoin):
self.OnLeave(self.game.evLeave.receive(self))
#@-node:jpenner.20090529173104.3:<<Joiner>>
#@nl
#@+others
#@+node:jpenner.20091003162445.1:Lobby
class Lobby(TokenClient):
def InitPersistent(self, owner, client):
TokenClient.InitPersistent(self, owner, client)
self.miDrawings = MiMenu(RgmiProjected(self.game.rgboard, DgProjectMiButton(self.Goto)))
self.miCmds = MiMenu([None, None, MiTypein(self.New, "DrawingName"), MiButton("New Drawing", self.NewBtn),
None, None, None, None, None, None, None, None, MiStatic("Last modified:"), MiDgText(self.StLastModified)])
OvMenu(self, client, MiMenuHoriz([self.miDrawings, self.miCmds], [65, 35]), OvMenu.FILL)
def New(self, stName):
if stName != "":
self.game.NewBoard(stName, self.client.cld.user)
def NewBtn(self):
self.New(self.miCmds.Value("DrawingName"))
def StLastModified(self):
return self.miDrawings.Value().StLastModified()
def Goto(self, board):
self.client.leaveGame(board)
#@-node:jpenner.20091003162445.1:Lobby
#@+node:jpenner.20090529173104.25:Runner
class RunnerWB(Runner):
def InitPersistent(self):
self.gameLobby = GameLobby()
Runner.InitPersistent(self)
def RunGame(self, client):
if (client.joinGame(GameLogin())):
while True:
board = client.joinGame(self.gameLobby)
client.joinGame(self.gameLobby.GameFromBoard(board))
class GameLogin(Game):
def GetRgclsTokTrans(self):
return [[AutoJoiner, login.LoginTerm]]
@Version(5)
class GameLobby(Game):
def InitPersistent(self):
self.rgboard = []
Game.InitPersistent(self)
def InitTransient(self):
Game.InitTransient(self)
self.mpboard_gameWB = {}
def GetRgclsTokTrans(self):
return [[AutoJoiner, Lobby]]
def GameFromBoard(self, board):
if not (board in self.mpboard_gameWB):
gameWB = GameWB(self, board)
def KillBoard():
del self.mpboard_gameWB[board]
gameWB.rgdgdie.append(KillBoard)
self.mpboard_gameWB[board] = gameWB
return gameWB
return self.mpboard_gameWB[board]
def NewBoard(self, stName, user):
self.rgboard.insert(0, Board(self, stName, user))
def StNameBoard(self, board):
cclient = 0
if board in self.mpboard_gameWB:
cclient = len(self.mpboard_gameWB[board].rgclient)
return board.stName + " (by " + board.user + ") [" + str(cclient) + "]"
def BoardTouched(self, board):
#haaaack
if board != self.rgboard[0]:
self.rgboard.remove(board)
self.rgboard.insert(0, board)
self.ensureRun() # redraw
def UpgradeFrom(self, versionOld):
if versionOld < 3:
for gameWB in self.rggameWB:
gameWB.gameLobby = self
if versionOld < 4:
self.rgboard = [game.rgtoken("whiteboard")[0].board for game in self.rggameWB]
for gameWB in self.rggameWB:
gameWB.finish()
if versionOld < 5:
del self.rggameWB
class GameWB(Game):
def InitPersistent(self, gameLobby, board):
self.gameLobby = gameLobby
self.board = board
Game.InitPersistent(self)
def InitTransient(self):
Game.InitTransient(self)
if not self.FDead():
self.board.chat.AttachToGame(self)
self.rgdgdie.append(self.board.chat.DetachFromGame)
def GetRgclsTokPers(self):
return [[Whiteboard, self.board]]
def GetRgclsTokTrans(self):
return [MsgScroller, Joiner, [AutoJoiner, Cursor], [AliveWithPlayers, CursorBlinker], AutoKiller]
def GetRgtagDraw(self):
return ["background", "solid", "cursor", "menu", "msgscroller"]
if __name__ == "__main__":
Run(RunnerWB, "whiteboard.marm")