from engine import * from basetoken import * from tpers import * from datetime import * from util import * import telnet import time import login import weakref 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 FSelectable(self): return True class Project(Ownable): def InitPersistent(self, owner, stName, user): Ownable.InitPersistent(self, owner) self.stName = stName self.user = user self.rgdrawing = [] self.rgscript = [] def NewBoard(self, stName, user): board = Board(self, stName, user) self.rgdrawing.insert(0, board) return board def NewSprite(self, stName, user, w, h): sprite = Sprite(self, stName, user, w, h) self.rgdrawing.insert(0, sprite) return sprite def DrawingTouched(self, drawing): if drawing != self.rgdrawing[0]: self.rgdrawing.remove(drawing) self.rgdrawing.insert(0, drawing) self.owner.DrawingTouched(drawing) def StName(self): return self.owner.StNameProject(self) def StLastModified(self): drawingLast = None for drawing in self.rgdrawing: if drawingLast == None or drawing.dtLastModified > drawingLast.dtLastModified: drawingLast = drawing if drawingLast != None: return drawingLast.StLastModified() return "never" def RgstMetadata(self): return ["by " + self.user, "", "Last modified:", self.StLastModified()] class Drawing(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.owner.StNameDrawing(self) def RgstMetadata(self): return [self.StType(), "by " + self.user, "", "Last modified", self.StLastModified()] 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, ascr = None): if len(self.rglayer) < 8: if ascr == None: ascr = ansi.Ascr(self.W(), self.H()) layerNew = Layer(ascr, 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 Touch(self): self.SetTimestamp() self.owner.DrawingTouched(self) def SetTimestamp(self): self.dtLastModified = datetime.now() @Version(3) class Board(Drawing): def StType(self): return "Board" def W(self): return config.W def H(self): return config.H def draw(self, ascr): for layer in reversed(self.rglayer): ascr.PutAscr(layer.ascr) 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("
") fl.write(ascr.Hst()) fl.write("
") with open(fn + ".ans", "w") as fl: fl.write(ascr.Ast()) 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() class Sprite(Drawing): def InitPersistent(self, owner, stName, user, w, h): self.w = w self.h = h Drawing.InitPersistent(self, owner, stName, user, [Layer(ansi.Ascr(w, h), "Frame 1")]) def StType(self): return "Sprite" def W(self): return self.w def H(self): return self.h def draw(self, ascr, x, y, iframe): ascr.PutAscr(self.rglayer[iframe].ascr, x, y) def RgstMetadata(self): return [self.StType(), "by " + self.user, "", str(self.w) + "x" + str(self.h), str(len(self.rglayer)) + " frames", "", "Last modified", self.StLastModified()] @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) 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 class Cursor(TokenClient): def InitPersistent(self, game, client): TokenClient.InitPersistent(self, game, client, "drawable", "cursor") self.fBlink = False self.cDontBlink = 0 self.pos = ansi.Pos(self.game.drawing.W(), self.game.drawing.H()) self.SetupMenus() self.SelectLayer(self.game.drawing.rglayer[0]) self.CreateDrawingToken() def CreateDrawingToken(self): WhiteboardDraw(self, self.client) def SetupMenus(self): 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 = self.MenuDrawing(miFg, miBg, miChars, miQuit) self.miChat = MiMenu([None, MiChat(self.client, 13, self.game.drawing.chat), MiTypein(self.SendMsg), None, miQuit, None]) self.rgmiLayer = RgmiProjected(self.game.drawing.rglayer, DgProjectMiButton(self.SelectLayer)) self.miLayers = self.MenuLayers(miQuit) self.ovPopup = OvPopup(self, self.client, MiTab.MiTabbed(["Drawing", self.cf], [self.StLayerTab(), self.miLayers], ["Chat", self.miChat])) miStatus = MiMenuHoriz([MiStatic("Hit for menu"), MiValue(miChars)]) miStatus.ListenForNotice(self.miChat) self.ovStatus = OvStatic(self, self.client, miStatus, OvStatic.BOTTOM) def MenuDrawing(self, miFg, miBg, miChars, miQuit): return MiMenu([None, miFg, miBg, None, miChars, None, MiButton("Save", self.Save), None, miQuit, None]) def MenuLayers(self, miQuit): return MiMenu(Rgseq([None], self.rgmiLayer, [None, MiButton("New Layer", self.NewLayer), MiButton("Move up", self.LayerUp), MiButton("Move down", self.LayerDown), None, MiToggle("Show One"), None, MiStatic("Rename selected layer:"), MiTypein(self.RenameLayer, "LayerName", 80), None, miQuit, None])) def StLayerTab(self): return "Layers" def Save(self): self.game.drawing.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.game.drawing.LayerByName(stLayer) != None: stLayer = None ilayer = ilayer + 1 layerNew = self.game.drawing.NewLayer(stLayer) if layerNew != None: self.SelectLayer(layerNew) return True def LayerUp(self): self.game.drawing.MoveLayer(self.GetLayer(), True) return True def LayerDown(self): self.game.drawing.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.game.drawing.chat.Add(ChlAct(self.client, st[4:])) else: self.game.drawing.chat.Add(ChlMsg(self.client, st)) def OnChat(self, chl): if type(chl) != ChlSys: self.miChat.FlagNotice() def run(self): with self.game.drawing.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.game.drawing.H() < config.H) or (self.pos.Y() < self.game.drawing.H() / 2): self.ovStatus.kplace = OvStatic.BOTTOM else: self.ovStatus.kplace = OvStatic.TOP def PutWb(self, ch): self.Put(ch, self.GetLayer().ascr) self.game.drawing.Touch() def Put(self, ch, ascr, xzOffset = 0, yzOffset = 0): 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() + xzOffset, self.pos.Y() + yzOffset) 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 XzYzScreenPic(self): layer = self.GetLayer() return ((config.W - layer.ascr.W()) / 2, (config.H - layer.ascr.H()) / 2) def FDrawCursor(self): return self.fBlink or self.cDontBlink > 0 def draw(self, ascr, client): if self.FDrawCursor(): 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, *self.XzYzScreenPic()) elif self.fBlink: self.Put(str(self.client.Cldg().iclient)[0], ascr, *self.XzYzScreenPic()) class CursorSprite(Cursor): def InitPersistent(self, game, client): Cursor.InitPersistent(self, game, client) self.blinkerAnimate = None def CreateDrawingToken(self): SpriteDraw(self, self.client) def MenuDrawing(self, miFg, miBg, miChars, miQuit): return MiMenu([None, miFg, miBg, None, miChars, None, miQuit, None]) def MenuLayers(self, miQuit): return MiMenu(Rgseq([None], self.rgmiLayer, [None, MiButton("New Frame", self.NewLayer), MiButton("Move up", self.LayerUp), MiButton("Move down", self.LayerDown), None, MiStatic("Rename selected frame:"), MiTypein(self.RenameLayer, "LayerName", 80), None, MiButton("Animate", self.Animate), None, miQuit, None])) def StLayerTab(self): return "Frames" def NewLayer(self): stLayer = "Frame " + str(len(self.game.drawing.rglayer) + 1) layer = self.GetLayer() ascr = ansi.Ascr(self.game.drawing.W(), self.game.drawing.H()) ascr.PutAscr(layer.ascr) layerNew = self.game.drawing.NewLayer(stLayer, ascr) if layerNew != None: self.SelectLayer(layerNew) return True def Animate(self): if (self.blinkerAnimate == None): self.blinkerAnimate = Blinker(self, self.SelectLayer, self.game.drawing.rglayer, interval = 300) self.ovPopup.SetSelection("animate", self.miLayers.MiByName("Animate")) else: self.blinkerAnimate.die() self.blinkerAnimate = None self.ovPopup.SetSelection("animate", None) def FDrawCursor(self): if self.blinkerAnimate: return False return Cursor.FDrawCursor(self) 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"): ascr.PutAscr(self.owner.GetLayer().ascr) else: self.game.drawing.draw(ascr) class SpriteDraw(TokenClient): def InitPersistent(self, owner, client): TokenClient.InitPersistent(self, owner, client, "drawable", "solid") def draw(self, ascr, client): if client == self.client: (xz, yz) = self.owner.XzYzScreenPic() x = xz + 1 y = yz + 1 layer = self.owner.GetLayer() ascr.PutAscr(layer.ascr, x, y) # draw border ascr.PutAch(ansi.MkAch(chr(218), ansi.WHITE | ansi.FBRIGHT), x - 1, y - 1) # top-left ascr.PutAch(ansi.MkAch(chr(191), ansi.WHITE | ansi.FBRIGHT), x + layer.ascr.W(), y - 1) # top-right ascr.PutAch(ansi.MkAch(chr(192), ansi.WHITE | ansi.FBRIGHT), x - 1, y + layer.ascr.H()) # bottom-left ascr.PutAch(ansi.MkAch(chr(217), ansi.WHITE | ansi.FBRIGHT), x + layer.ascr.W(), y + layer.ascr.H()) # bottom-right for yT in (y - 1, y + layer.ascr.H()): ascr.PutSt(chr(196) * layer.ascr.W(), x, yT, ansi.WHITE | ansi.FBRIGHT) # - for xT in (x - 1, x + layer.ascr.W()): for yT in xrange(y, y + layer.ascr.H()): ascr.PutAch(ansi.MkAch(chr(179), ansi.WHITE | ansi.FBRIGHT), xT, yT) # | 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) 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) 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 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) class Joiner(LeaveJoinToken): def InitPersistent(self, owner): Token.InitPersistent(self, owner) self.msgScroller = self.game.rgtoken("msgscroller")[0] self.board = self.game.drawing 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")) class Lobby(TokenClient): def InitPersistent(self, owner, client): TokenClient.InitPersistent(self, owner, client) drawing = client.Cldg(self.game).drawingSelected if drawing == None: self.lobbyCurrent = LobbyProject(self, client) else: self.lobbyCurrent = LobbyBoard(self, client, drawing.owner, drawing) def SwitchToLobby(self, lobbyNew): lobbyOld = self.lobbyCurrent self.lobbyCurrent = lobbyNew lobbyOld.die() class LobbyI(TokenClient): def InitPersistent(self, owner, client, objSelected = None, *rgmiListTop): TokenClient.InitPersistent(self, owner, client) rgmiList = RgmiProjected(self.RgObj(), DgProjectMiButton(self.OnObjSelected)) if rgmiListTop != None: rgmiList = Rgseq(rgmiListTop, rgmiList) self.miDrawings = MiMenu(rgmiList) if objSelected: mi = self.miDrawings.MiByName(objSelected.StName()) self.miDrawings.selMi.SetSelected(mi) self.miCmds = self.CreateMiCmds() OvMenu(self, client, MiMenuHoriz([self.miDrawings, self.miCmds], [65, 35]), OvMenu.FILL) def RgObj(self): "Return the list of objects we are selecting from" raise "not implemented" def OnObjSelected(self, obj): "Called when an object is selected by the user" raise "not implemented" def RgstMetadata(self, obj): "Return a list of strings containing user-readable metadata about the object" raise "not implemented" def StMetadata(self): try: return "\n".join(self.RgstMetadata(self.miDrawings.Value())) except: return "" def MiTypein_MiButton_DgNew(self, stBtnLabel, stMiTypein, dgOnSelect): def NewI(*rgarg): stName = self.miCmds.Value(stMiTypein) if stName != "": dgOnSelect(stName) return (MiTypein(NewI, stMiTypein), MiButton(stBtnLabel, NewI), NewI) def MiTypein_MiButton(self, stBtnLabel, stMiTypein, dgOnSelect): return self.MiTypein_MiButton_DgNew(stBtnLabel, stMiTypein, dgOnSelect)[:2] class LobbyBoard(LobbyI): def InitPersistent(self, owner, client, project, drawing = None): self.project = project LobbyI.InitPersistent(self, owner, client, drawing, MiButton("<-- Back to projects", self.Back), None) def CreateMiCmds(self): miTypeinBoard, miBtnNewBoard = self.MiTypein_MiButton("New Board", "BoardName", self.NewBoard) miTypeinSpr, miBtnNewSpr, dgNewSprite = self.MiTypein_MiButton_DgNew("New Sprite", "SpriteName", self.NewSprite) miTypeinW = MiTypein(dgNewSprite, "w") miTypeinW.SetValue("1") miTypeinH = MiTypein(dgNewSprite, "h") miTypeinH.SetValue("1") self.miDimensions = MiMenuHoriz([MiStatic("W:"), miTypeinW, MiStatic("H:"), miTypeinH]) return MiMenu([None, None, miTypeinBoard, miBtnNewBoard, None, None, miTypeinSpr, self.miDimensions, miBtnNewSpr, None, None, None, None, None, MiDgText(self.StMetadata)]) def RgObj(self): return self.project.rgdrawing def OnObjSelected(self, board): self.client.leaveGame(board) def NewBoard(self, stName): self.OnObjSelected(self.project.NewBoard(stName, self.client.cld.user)) def NewSprite(self, stName): try: w = int(self.miDimensions.Value("w")) h = int(self.miDimensions.Value("h")) if 0 < w < config.W and 0 < h < config.H: self.OnObjSelected(self.project.NewSprite(stName, self.client.cld.user, w, h)) except: pass def RgstMetadata(self, board): if board != None: return board.RgstMetadata() return self.project.RgstMetadata() def Back(self): self.owner.SwitchToLobby(LobbyProject(self.owner, self.client, self.project)) class LobbyProject(LobbyI): def CreateMiCmds(self): miTypein, miBtnNew = self.MiTypein_MiButton("New Project", "ProjName", self.New) return MiMenu([None, None, miTypein, miBtnNew, None, None, None, None, None, None, None, None, MiDgText(self.StMetadata)]) def StNewObj(self): return "New Project" def RgObj(self): return self.game.rgproject def OnObjSelected(self, project): self.owner.SwitchToLobby(LobbyBoard(self.owner, self.client, project)) def New(self, stName): project = self.game.NewProject(stName, self.client.cld.user) self.OnObjSelected(project) def RgstMetadata(self, project): return project.RgstMetadata() class RunnerWB(Runner): def InitPersistent(self): self.gameLobby = GameLobby() Runner.InitPersistent(self) def RunGame(self, client): if (client.joinGame(GameLogin())): client.Cldg(self.gameLobby).drawingSelected = None while True: drawing = client.joinGame(self.gameLobby) client.Cldg(self.gameLobby).drawingSelected = drawing client.joinGame(self.gameLobby.GameFromDrawing(drawing)) class GameLogin(Game): def GetRgclsTokTrans(self): return [[AutoJoiner, login.LoginTerm]] @Version(6) class GameLobby(Game): def InitPersistent(self): self.rgproject = [] Game.InitPersistent(self) def InitTransient(self): Game.InitTransient(self) self.mpdrawing_game = {} def GetRgclsTokTrans(self): return [[AutoJoiner, Lobby]] def GameFromDrawing(self, drawing): if not (drawing in self.mpdrawing_game): if drawing.StType() == "Board": game = GameWB(self, drawing) elif drawing.StType() == "Sprite": game = GameSprEdit(self, drawing) else: assert False, "Lobby not prepared to deal with drawing of type " + drawing.StType() def KillBoard(): del self.mpdrawing_game[drawing] game.rgdgdie.append(KillBoard) self.mpdrawing_game[drawing] = game return game return self.mpdrawing_game[drawing] def CclientDrawing(self, drawing): if drawing in self.mpdrawing_game: return len(self.mpdrawing_game[drawing].rgclient) return 0 def StNameProject(self, project): return project.stName + " [" + str(sum([self.CclientDrawing(drawing) for drawing in project.rgdrawing])) + "]" def StNameDrawing(self, drawing): return drawing.stName + " [" + str(self.CclientDrawing(drawing)) + "]" def NewProject(self, stName, user): proj = Project(self, stName, user) self.rgproject.insert(0, proj) return proj def DrawingTouched(self, drawing): project = drawing.owner if project != self.rgproject[0]: self.rgproject.remove(project) self.rgproject.insert(0, project) #haaaack 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 if versionOld < 6: project = Project(self, "Drawings", "Willy Marmot") for board in self.rgboard: board.TransferToOwner(project) project.rgdrawing.append(board) del self.rgboard self.rgproject = [project] self.mpuser_cldg = {} # ugh, upgrading parent classes is broken in our model :( class GameWB(Game): def InitPersistent(self, gameLobby, board): self.gameLobby = gameLobby self.drawing = board Game.InitPersistent(self) def InitTransient(self): Game.InitTransient(self) if not self.FDead(): self.drawing.chat.AttachToGame(self) self.rgdgdie.append(self.drawing.chat.DetachFromGame) def ClsCursor(self): return Cursor def GetRgclsTokTrans(self): return [MsgScroller, Joiner, [AutoJoiner, self.ClsCursor()], [AliveWithPlayers, CursorBlinker], AutoKiller] def GetRgtagDraw(self): return ["background", "solid", "cursor", "menu", "msgscroller"] class GameSprEdit(GameWB): def ClsCursor(self): return CursorSprite if __name__ == "__main__": Run(RunnerWB, "whiteboard.marm")