def notesflush(self): dprint("notes flush") fd = open("./mapper/notes", "w") for note in self.notes: line = "%s\x19%s\x19%s" % (note[0], note[1], note[2]) fd.write("%s\n" % line) fd.close()
def notesflush(self): dprint('notes flush') fd = open('./mapper/notes', 'w') for note in self.notes: line = '%s\x19%s\x19%s' % (note[0], note[1], note[2]) fd.write('%s\n' % line) fd.close()
def connect(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((self.host, self.port)) self.sock.send(b'\x1bbc 1\n') self.xsock[0] = self.sock self.connected = True dprint('CONNECTED', self, self.sock)
def createchannel(self, chgrpwidget, channels, title): """Create channel in specified channel group. """ tabwidget = chgrpwidget.qtabwidget css = self.parent.styleSheet() qconsole = QConsoleWindow(tabwidget.getTabParent(), css) qconsole.hide() qconsole.setupdowncallback(self.updowncallback) qconsole.setcommandchangedcallback(self.commandchangedcallback) def __close(): tabwidget.removeWidget(qconsole) menu = QtGui.QMenu(self.parent) if '$all' not in channels and '$battle' not in channels: a1 = QtGui.QAction('Close', self.parent) a1.triggered.connect(__close) menu.addAction(a1) tabwidget.addTab(qconsole, title, menu) qconsole.show() qconsole.chanlist = channels # check if single input if len(channels) < 2: # check if channel only if channels[0][0] == '#': builtin = ( 'bat', 'bs', 'd3', 'ghost', 'ifin', 'lfp', 'newbie', 'race', 'suomi', 'battlebot', 'chat', 'eso', 'hockey', 'imud', 'magical', 'sports', 'tunes', 'boardgaming', 'client', 'football', 'houses', 'infalert', 'mudcon', 'politics', 'sales', 'stream', 'wanted' ) # this actually became annoying.. #if channels[0][1:] in builtin: # qconsole.setcommandprefix('%s ' % (channels[0][1:])) #else: # qconsole.setcommandprefix('%s say ' % (channels[0][1:])) if channels[0][0] == '!': # add prefix for talking over tells to player qconsole.setcommandprefix('tell %s ' % (channels[0][1:])) if channels[0] == '$readme': if os.path.exists('README'): readme = 'README' if os.path.exists('./client/README'): readme = './client/README' fd = open(readme, 'r') dprint('readme', 'rb') lines = fd.readlines() for line in lines: line = bytes(line, 'utf8').strip(b'\r\n').replace(b'\\x1b', b'\x1b') self.addlinetoconsole(qconsole, line) fd.close() qconsole.commandEvent = self.commandEvent qconsole.show() return qconsole
def event_lineunknown(self, event, line): #l:b'A little bunny is such a sweet sight, fluffy like a ball of cotton and as' #l:b'white too. You cannot help but adore this tiny cute animal.' #l:b'He is in excellent shape.' #l:b'He looks hungry.' if self.look_intercept: # He looks # She looks # It looks x = line.find(b'looks') if x < 6 and x > -1: # ignore this line return True if line.endswith(b'shape.'): tmp = ' '.join(self.tmp) phrase = self.pendinglooks.pop(0) self.game.pushevent( 'lineunknown', b'\x1b#99ff99mAdded looks of [' + bytes(phrase, 'utf8') + b'] to MOB-LORE.') self.moblore['looks'][phrase] = tmp self.dumplore() self.look_intercept = False self.do_nextlook() return True self.tmp.append(line.decode('utf8')) return True #l:b'That is not possible.' if line.find( b'That is not possible.') == 0 and self.consider_intercept: self.consider_intercept = False # do nothing because it was invalid entry = self.pendingconsiders.pop(0) self.do_nextconsider() return True # At the moment these are useless #l:b'You make a small puddle on the floor.' #if line.find(b'You make a small puddle on the floor.') == 0 and self.consider_intercept: # return True #l:b"Not a valid adverb, 'blurred'." #if line.find(b'Not a valid adverb, ') == 0 and self.consider_intercept: # return True #l:b'\x1b[1;32msix spotted ladybird\x1b[0m' if line.find(b'\x1b[1;32m') == 0 and line.count( b'\x1b') == 2 and line.find(b':') < 0: mob = line[line.find(b'm') + 1:line.rfind(b'\x1b')].decode( 'utf8', 'ignore') mob = mob.replace(',', '') if mob.find(' is') > -1: mob = mob[0:mob.find(' is')].strip() if mob.startswith('a '): mob = mob[2:] if mob.startswith('A '): mob = mob[2:] dprint('mob:%s' % mob) self.game.pushevent('mobdetected', mob)
def do_nextconsider(self): if not self.consider_intercept: if len(self.pendingconsiders) < 1: # unlock command group and exit since # we have finished doing our considers self.do_nextlook() return phrase = self.pendingconsiders[0][0] self.consider_intercept = True dprint('considering `%s`' % phrase) self.game.command('consider %s' % phrase, self)
def event_lineunknown(self, event, line): #l:b'A little bunny is such a sweet sight, fluffy like a ball of cotton and as' #l:b'white too. You cannot help but adore this tiny cute animal.' #l:b'He is in excellent shape.' #l:b'He looks hungry.' if self.look_intercept: # He looks # She looks # It looks x = line.find(b'looks') if x < 6 and x > -1: # ignore this line return True if line.endswith(b'shape.'): tmp = ' '.join(self.tmp) phrase = self.pendinglooks.pop(0) self.game.pushevent('lineunknown', b'\x1b#99ff99mAdded looks of [' + bytes(phrase, 'utf8') + b'] to MOB-LORE.') self.moblore['looks'][phrase] = tmp self.dumplore() self.look_intercept = False self.do_nextlook() return True self.tmp.append(line.decode('utf8')) return True #l:b'That is not possible.' if line.find(b'That is not possible.') == 0 and self.consider_intercept: self.consider_intercept = False # do nothing because it was invalid entry = self.pendingconsiders.pop(0) self.do_nextconsider() return True # At the moment these are useless #l:b'You make a small puddle on the floor.' #if line.find(b'You make a small puddle on the floor.') == 0 and self.consider_intercept: # return True #l:b"Not a valid adverb, 'blurred'." #if line.find(b'Not a valid adverb, ') == 0 and self.consider_intercept: # return True #l:b'\x1b[1;32msix spotted ladybird\x1b[0m' if line.find(b'\x1b[1;32m') == 0 and line.count(b'\x1b') == 2 and line.find(b':') < 0: mob = line[line.find(b'm') + 1:line.rfind(b'\x1b')].decode('utf8', 'ignore') mob = mob.replace(',', '') if mob.find(' is') > -1: mob = mob[0:mob.find(' is')].strip() if mob.startswith('a '): mob = mob[2:] if mob.startswith('A '): mob = mob[2:] dprint('mob:%s' % mob) self.game.pushevent('mobdetected', mob)
def command(self, command, group="default"): if type(command) is str: command = bytes(command, "utf8") if self.cmdgrouplock is not None and group != self.cmdgrouplock: self.cmdpending.append(command) self.pushevent("lineunknown", b"\x1b#ff9999mThe command `" + command + b"` is pending!") return dprint("command", command) self.c.writeline(command)
def command(self, command, group='default'): if type(command) is str: command = bytes(command, 'utf8') if self.cmdgrouplock is not None and group != self.cmdgrouplock: self.cmdpending.append(command) self.pushevent( 'lineunknown', b'\x1b#ff9999mThe command `' + command + b'` is pending!') return dprint('command', command) self.c.writeline(command)
def commandEvent(self, line): """When the command input on any channel window changes. """ # set history line, only if not a movement command if line not in {'n', 's', 'w', 'e', 'nw', 'ne', 'sw', 'se'}: self.chistory[-1] = line # make new history line self.chistory.append('') res = self.game.pushevent('command', line) if res is True or (type(res) == tuple and res[0] is True): dprint('dropped command') # the command was intercepted, processed, and the handler # has requested that we drop the command and not forward # it to the game return self.game.command(line)
def update(self): if len(self.spells) < 1: return self.resize(self.width(), len(self.spells) * 30) hpe = self.height() / len(self.spells) ct = time.time() cy = 0 for who in self.spells: toremove = [] for spellname in self.spells[who]: spell = self.spells[who][spellname] w = spell[0] l = spell[1] c = spell[2] m = spell[3] st = spell[4] # get current tick in real time (counting seconds per #) cc = c - (ct - st) * 0.35 if cc < 0 or m <= 0: toremove.append(spellname) continue width = (cc / m) * self.width() w.move(0, cy) w.resize(width, hpe) l.move(0, cy) l.resize(self.width(), hpe) l.setText('%s (%.01f)' % (spellname.replace('_', ' '), cc)) l.raise_() cy = cy + hpe for r in toremove: spell = self.spells[who][r] w = spell[0] l = spell[1] l.hide() l.setParent(None) w.hide() w.setParent(None) del self.spells[who][r] dprint('removed spell', r)
def do_nextlook(self): if len(self.pendinglooks) < 1: self.game.unlockcmdgroup(self) return # only look at things we have never looked at before while True: if len(self.pendinglooks) < 1: self.game.unlockcmdgroup(self) return phrase = self.pendinglooks[0] if phrase in self.moblore['looks']: dprint('[%s] already in looks' % phrase) self.pendinglooks.pop(0) continue break self.look_intercept = True self.tmp = [] self.game.command('look %s' % phrase, self)
def event_blockunknown(self, event, block): #b:b'\x1b<10spec_skill\x1b|The final estimation is that Caretaker of the Temple can easily reduce you to\r\nminced meat, so run for your life.\r\n\x1b>10' #b:b'\x1b<10spec_skill\x1b|The final estimation is that Monarch butterfly looks quite skilled, beware.\r\n\x1b>10' #b:b"\x1b<10spec_skill\x1b|The final estimation is that Warthog's power overwhelms your mind! You PANIC!!\r\n\x1b>10" if block.find( b'\x1b<10spec_skill\x1b|The final estimation is that') == 0: i = block.find(b'that') + 5 x = findmulti(block, (b'can', b'looks', b'power', b'and', b'has'), i) mob_basename = block[i:x].strip() desc = block[x:] if mob_basename.endswith(b'\'s'): mob_basename = mob_basename[0:-2] mob_basename = mob_basename.decode('utf8') desc = desc.decode('utf8') if desc.find('\r') > -1: desc = desc[0:desc.find('\r')].strip() print('mob_basename:[%s] desc:[%s]' % (mob_basename, desc)) if self.consider_intercept: entry = self.pendingconsiders.pop(0) self.moblore['descnametoname'][entry[1]] = mob_basename else: entry = None mylevel = self.playerlevel # if we do not have our level then the consideration # can be quite meaningless really... right? if mylevel > -1: if mylevel not in self.moblore['consider-base']: self.moblore['consider-base'][mylevel] = {} if mylevel not in self.moblore['consider-full']: self.moblore['consider-full'][mylevel] = {} self.moblore['consider-base'][mylevel][mob_basename] = desc if entry is not None: self.moblore['consider-full'][mylevel][entry[1]] = desc self.game.pushevent( 'lineunknown', b'\x1b#99ff99mAdded level of [' + bytes(mob_basename, 'utf8') + b'] to MOB-LORE.') self.dumplore() if self.consider_intercept: self.consider_intercept = False # remove everything else to keep from just wasting # bandwidth and time trying them when we have already # found the correct one _pendingconsiders = [] for p in self.pendingconsiders: if p[1] != entry[1]: _pendingconsiders.append(p) self.pendingconsiders = _pendingconsiders self.pendinglooks.append(mob_basename) self.do_nextconsider() return True else: # take a quick look at the mob dprint('doing quick look at [%s]' % mob_basename) self.game.lockcmdgroup(self) self.pendinglooks.append(mob_basename) self.do_nextlook() elif block.find(b'\x1b<10spec_skill') == 0 and self.consider_intercept: # drop it return True
def event_batmapper(self, event, thiszone, xid, lastmove, desc, moves): dprint('thiszone', thiszone) dprint('thisroom', xid) dprint('lastmove', lastmove) dprint('desc', desc[0:10].replace('\n', '').replace('\r', '')) dprint('moves', moves) _moves = moves.split(',') moves = set() mi = { 'n': 's', 's': 'n', 'e': 'w', 'w': 'e', 'u': 'd', 'd': 'u', 'nw': 'se', 'ne': 'sw', 'sw': 'ne', 'se': 'nw', } m = { 'north': 'n', 'northeast': 'ne', 'east': 'e', 'southeast': 'se', 'south': 's', 'southwest': 'sw', 'west': 'w', 'northwest': 'nw', 'up': 'u', 'down': 'd' } for move in _moves: if move in m: moves.add(m[move]) else: moves.add(move) # normalize it if lastmove in m: lastmove = m[lastmove] lastmoveinvert = mi[lastmove] else: lastmoveinvert = None if thiszone not in self.batmap: self.batmap[thiszone] = {} zone = self.batmap[thiszone] if xid not in zone: zone[xid] = {} zone[xid]['forward'] = set() zone[xid]['backward'] = set() zone[xid]['desc'] = None zone[xid]['moves'] = None zone[xid]['entered'] = set() zone[xid]['exited'] = set() zone[xid]['seenmobs'] = set() if self.lastbatmapper is not None: lastzone = self.lastbatmapper[0] lastxid = self.lastbatmapper[1] if lastzone == thiszone: # add backward link dprint('lastmoveinvert:%s lastmove:%s' % (lastmoveinvert, lastmove)) zone[xid]['backward'].add( ((lastzone, lastxid), lastmoveinvert)) # add forward link zone[lastxid]['forward'].add(((thiszone, xid), lastmove)) else: # mark we entered here zone[xid]['entered'].add(lastzone) zone[xid]['backward'].add( ((lastzone, lastxid), lastmoveinvert)) # mark we exited here self.batmap[lastzone][lastxid]['exited'].add(thiszone) self.batmap[lastzone][lastxid]['forward'].add( ((thiszone, xid), lastmove)) else: if self.wasoutside is True: # we came from the world zone[xid]['entered'].add('world') if zone[xid]['desc'] is not None and zone[xid]['desc'] != desc: # well.. we must be in a maze.. or something crazy self.game.pushevent( 'lineunknown', b'\x1b#ff9999mwarning: \x1b#ffffffmmapper plugin detected possible maze!' ) zone[xid]['desc'] = desc zone[xid]['moves'] = moves dprint('added entry zone:%s xid:%s moves:%s' % (thiszone, xid, moves)) self.wasoutside = False self.lastbatmapper = (thiszone, xid, lastmove, desc, moves) self.batmapflush() self.update()
def event_batmapper(self, event, thiszone, xid, lastmove, desc, moves): dprint("thiszone", thiszone) dprint("thisroom", xid) dprint("lastmove", lastmove) dprint("desc", desc[0:10].replace("\n", "").replace("\r", "")) dprint("moves", moves) _moves = moves.split(",") moves = set() mi = { "n": "s", "s": "n", "e": "w", "w": "e", "u": "d", "d": "u", "nw": "se", "ne": "sw", "sw": "ne", "se": "nw", } m = { "north": "n", "northeast": "ne", "east": "e", "southeast": "se", "south": "s", "southwest": "sw", "west": "w", "northwest": "nw", "up": "u", "down": "d", } for move in _moves: if move in m: moves.add(m[move]) else: moves.add(move) # normalize it if lastmove in m: lastmove = m[lastmove] lastmoveinvert = mi[lastmove] else: lastmoveinvert = None if thiszone not in self.batmap: self.batmap[thiszone] = {} zone = self.batmap[thiszone] if xid not in zone: zone[xid] = {} zone[xid]["forward"] = set() zone[xid]["backward"] = set() zone[xid]["desc"] = None zone[xid]["moves"] = None zone[xid]["entered"] = set() zone[xid]["exited"] = set() zone[xid]["seenmobs"] = set() if self.lastbatmapper is not None: lastzone = self.lastbatmapper[0] lastxid = self.lastbatmapper[1] if lastzone == thiszone: # add backward link dprint("lastmoveinvert:%s lastmove:%s" % (lastmoveinvert, lastmove)) zone[xid]["backward"].add(((lastzone, lastxid), lastmoveinvert)) # add forward link zone[lastxid]["forward"].add(((thiszone, xid), lastmove)) else: # mark we entered here zone[xid]["entered"].add(lastzone) zone[xid]["backward"].add(((lastzone, lastxid), lastmoveinvert)) # mark we exited here self.batmap[lastzone][lastxid]["exited"].add(thiszone) self.batmap[lastzone][lastxid]["forward"].add(((thiszone, xid), lastmove)) else: if self.wasoutside is True: # we came from the world zone[xid]["entered"].add("world") if zone[xid]["desc"] is not None and zone[xid]["desc"] != desc: # well.. we must be in a maze.. or something crazy self.game.pushevent( "lineunknown", b"\x1b#ff9999mwarning: \x1b#ffffffmmapper plugin detected possible maze!" ) zone[xid]["desc"] = desc zone[xid]["moves"] = moves dprint("added entry zone:%s xid:%s moves:%s" % (thiszone, xid, moves)) self.wasoutside = False self.lastbatmapper = (thiszone, xid, lastmove, desc, moves) self.batmapflush() self.update()
def findpath(self, goalcheck, usegg=True): """This will find all paths that satisfy the goal check function provided. This will find all paths that satisfy the goal check function provided. goalcheck - shall be a function taking the appropriate arguments usegg - uses geometric grid to determine if rooms have been visited """ if self.lastbatmapper is None: self.game.pushevent("lineunknown", b"mapper: not inside zone - assuming your in the world (try moving)!") return [] thiszone = self.lastbatmapper[0] zone = self.batmap[thiszone] thisxid = self.lastbatmapper[1] goal = [] visited = set() gg = set() gg = {} gg[(0, 0, 0)] = (thiszone, thisxid) bugs = [] bugs.append((thiszone, thisxid, [(thiszone, thisxid, "start")], 0, 0, 0)) amap = self.amap if goalcheck is not None: res = goalcheck(thiszone, thisxid, gg, (0, 0, 0)) if res is not False and res is not None: goal.append(([(thiszone, thisxid, "start")], res)) visited.add((thiszone, thisxid)) while len(bugs) > 0: _bugs = [] # iterate through parents letting them create child bugs for thiszone, thisxid, history, tx, ty, tz in bugs: zone = self.batmap[thiszone] room = zone[thisxid] forward = room["forward"] backward = room["backward"] _combined = set() for action in forward: _combined.add(action) for action in backward: _combined.add(action) for action in _combined: tozone, toxid = action[0] if (tozone, toxid) in visited: # if we been here before dont go back to it continue tomove = action[1] # create new child bug that inherits parent history nhistory = history + [(tozone, toxid, tomove)] if tx is not None and tomove in amap: ggoff = amap[tomove] cx = tx + ggoff[0] cy = ty + ggoff[1] cz = tz + ggoff[2] if (cx, cy, cz) in gg: # it seems most dungeons do not have a straight forward # geometric grid representation for vertical layers which # means this fails to eliminate all visited rooms.. so we # just have to be aware of it pass gg[(cx, cy, cz)] = (tozone, toxid) else: cx = None cy = None cz = None dprint("LOST GEO GRID with %s:%s" % (tx, tomove)) _bugs.append((tozone, toxid, nhistory, cx, cy, cz)) if goalcheck is not None: res = goalcheck(tozone, toxid, gg, (cx, cy, cz)) if res is not False and res is not None: goal.append((nhistory, res)) visited.add((tozone, toxid)) # parent die and children become parents bugs = _bugs self.game.pushevent( "lineunknown", bytes(" Searched %s/%s/%s Rooms" % (len(visited), len(zone), len(gg)), "utf8") ) # should have zero or more goals if goalcheck is None: return gg else: return goal
def event_command(self, event, command): parts = command.split(" ") if len(parts) > 0 and parts[0] == "mapper": if len(parts) > 1 and parts[1] == "totals": zonecount = 0 roomcount = 0 for zone in self.batmap: zonecount += 1 for room in zone: roomcount += 1 self.game.pushevent( "lineunknown", bytes("\x1b#ffffffmapper: tracking %s zones and %s rooms!" % (zonecount, roomcount), "utf8"), ) if len(parts) > 1 and parts[1] == "addnote": note = " ".join(parts[2:]) if self.lastbatmapper is None: if self.lastcord is not None: cx = self.lastcord[0] cy = self.lastcord[1] self.notes.append([cx, cy, note, None]) self.notesflush() # specify to drop propagation of event and not to forward command self.game.pushevent("lineunknown", b"mapper: added note to world") return (True, True) else: zonename = self.lastbatmapper[0] roomname = self.lastbatmapper[1] room = self.batmap[zonename][roomname] if "notes" not in room: room["notes"] = [] room["notes"].append(note) self.game.pushevent("lineunknown", b"mapper: added note to dungeon") if len(parts) > 1 and parts[1] == "navtoroom": if len(parts) < 3: self.game.pushevent("lineunknown", b"mapper: need target room name") else: pass if len(parts) > 1 and parts[1] == "tracemalloc": ss = tracemalloc.take_snapshot() top_stats = ss.statistics("lineno") for stat in top_stats[0:30]: print(stat) if len(parts) > 1 and parts[1] == "listnotes": if self.lastbatmapper is None: self.game.pushevent("lineunknown", b"mapper: not inside dungeon (look at map for world maybe..)") else: zonename = self.lastbatmapper[0] zone = self.batmap[zonename] for roomname in zone: room = zone[roomname] if "notes" in room: self.game.pushevent("lineunknown", b" " + bytes(roomname, "utf8")) for note in room["notes"]: self.game.pushevent("lineunknown", b" " + bytes(note, "utf8")) if len(parts) > 1 and parts[1] == "findout": self.game.pushevent("lineunknown", b"\x1b#ffffffmmapper: Entrance And/Or Exit Shortest Path") goal = self.findpath(self.goalcheck_enterorexit) for history, extra in goal: zonename = history[-1][0] roomname = history[-1][1] zone = self.batmap[zonename] room = zone[roomname] if len(room["entered"]) > 0: prefix = [] for txt in room["entered"]: prefix.append("%s" % txt) prefix = b" (out)" + bytes("|".join(prefix), "utf8") self.game.pushevent("lineunknown", prefix) if len(room["exited"]) > 0: prefix = [] for txt in room["exited"]: prefix.append("%s" % txt) prefix = b" (in)" + bytes("|".join(prefix), "utf8") self.game.pushevent("lineunknown", prefix) line = [] # drop the first node history = history[1:] for zonename, roomname, action in history: line.append("%s->" % action) line = bytes("".join(line), "utf8") self.game.pushevent("lineunknown", b" \x1b#99ff99m->" + line) if len(parts) > 1 and parts[1] == "findnew": self.game.pushevent("lineunknown", b"\x1b#ffffffmmapper: Unexplored Rooms") # gg = self.findpath(None) gg = {} def __goalcheck_newcheck(zonename, roomname, _, coff): zone = self.batmap[zonename] room = zone[roomname] amap = self.amap havedonemoves = set() for zoneandroom, move in room["backward"]: havedonemoves.add(move) for zoneandroom, move in room["forward"]: havedonemoves.add(move) # dprint('goal check', zonename, roomname, havedonemoves, room['moves']) for move in room["moves"]: if move not in havedonemoves: if coff[0] is not None and move in amap: ggoff = amap[move] cx = coff[0] + ggoff[0] cy = coff[1] + ggoff[1] cz = coff[2] + ggoff[2] if (cx, cy, cz) in gg: # nope, we been here before continue return (cx, cy, cz) else: return (None, None, None) return False goal = self.findpath(__goalcheck_newcheck) for x in range(0, min(len(goal), 15)): dprint("goal", goal[x][1]) history = goal[x][0] tx, ty, tz = goal[x][1] endzonename = history[-1][0] endroomname = history[-1][1] line = [] # drop the first node for zonename, roomname, action in history: line.append("%s->" % action) # figure out which moves have never been made goalroom = self.batmap[endzonename][endroomname] havedonemoves = set() for zoneandroom, move in goalroom["backward"]: havedonemoves.add(move) for zoneandroom, move in goalroom["forward"]: havedonemoves.add(move) sub = [] for move in goalroom["moves"]: if move not in havedonemoves: if tx is not None and move in self.amap: ggoff = self.amap[move] cx = tx + ggoff[0] cy = ty + ggoff[1] cz = tz + ggoff[2] if (cx, cy, cz) in gg: # nope, we been here before continue sub.append(move) if len(sub) > 0: line.append("\x1b#9999ddm[%s]" % "|".join(sub)) line = bytes("".join(line), "utf8") self.game.pushevent("lineunknown", b" \x1b#99ff99m->" + line) return (True, True)
def event_command(self, event, command): parts = command.split(' ') if len(parts) > 0 and parts[0] == 'mapper': if len(parts) > 1 and parts[1] == 'totals': zonecount = 0 roomcount = 0 for zone in self.batmap: zonecount += 1 for room in zone: roomcount += 1 self.game.pushevent( 'lineunknown', bytes( '\x1b#ffffffmapper: tracking %s zones and %s rooms!' % (zonecount, roomcount), 'utf8')) if len(parts) > 1 and parts[1] == 'addnote': note = ' '.join(parts[2:]) if self.lastbatmapper is None: if self.lastcord is not None: cx = self.lastcord[0] cy = self.lastcord[1] self.notes.append([cx, cy, note, None]) self.notesflush() # specify to drop propagation of event and not to forward command self.game.pushevent('lineunknown', b'mapper: added note to world') return (True, True) else: zonename = self.lastbatmapper[0] roomname = self.lastbatmapper[1] room = self.batmap[zonename][roomname] if 'notes' not in room: room['notes'] = [] room['notes'].append(note) self.game.pushevent('lineunknown', b'mapper: added note to dungeon') if len(parts) > 1 and parts[1] == 'navtoroom': if len(parts) < 3: self.game.pushevent('lineunknown', b'mapper: need target room name') else: pass if len(parts) > 1 and parts[1] == 'tracemalloc': ss = tracemalloc.take_snapshot() top_stats = ss.statistics('lineno') for stat in top_stats[0:30]: print(stat) if len(parts) > 1 and parts[1] == 'listnotes': if self.lastbatmapper is None: self.game.pushevent( 'lineunknown', b'mapper: not inside dungeon (look at map for world maybe..)' ) else: zonename = self.lastbatmapper[0] zone = self.batmap[zonename] for roomname in zone: room = zone[roomname] if 'notes' in room: self.game.pushevent( 'lineunknown', b' ' + bytes(roomname, 'utf8')) for note in room['notes']: self.game.pushevent( 'lineunknown', b' ' + bytes(note, 'utf8')) if len(parts) > 1 and parts[1] == 'findout': self.game.pushevent( 'lineunknown', b'\x1b#ffffffmmapper: Entrance And/Or Exit Shortest Path') goal = self.findpath(self.goalcheck_enterorexit) for history, extra in goal: zonename = history[-1][0] roomname = history[-1][1] zone = self.batmap[zonename] room = zone[roomname] if len(room['entered']) > 0: prefix = [] for txt in room['entered']: prefix.append('%s' % txt) prefix = b' (out)' + bytes('|'.join(prefix), 'utf8') self.game.pushevent('lineunknown', prefix) if len(room['exited']) > 0: prefix = [] for txt in room['exited']: prefix.append('%s' % txt) prefix = b' (in)' + bytes('|'.join(prefix), 'utf8') self.game.pushevent('lineunknown', prefix) line = [] # drop the first node history = history[1:] for zonename, roomname, action in history: line.append('%s->' % action) line = bytes(''.join(line), 'utf8') self.game.pushevent('lineunknown', b' \x1b#99ff99m->' + line) if len(parts) > 1 and parts[1] == 'findnew': self.game.pushevent('lineunknown', b'\x1b#ffffffmmapper: Unexplored Rooms') #gg = self.findpath(None) gg = {} def __goalcheck_newcheck(zonename, roomname, _, coff): zone = self.batmap[zonename] room = zone[roomname] amap = self.amap havedonemoves = set() for zoneandroom, move in room['backward']: havedonemoves.add(move) for zoneandroom, move in room['forward']: havedonemoves.add(move) #dprint('goal check', zonename, roomname, havedonemoves, room['moves']) for move in room['moves']: if move not in havedonemoves: if coff[0] is not None and move in amap: ggoff = amap[move] cx = coff[0] + ggoff[0] cy = coff[1] + ggoff[1] cz = coff[2] + ggoff[2] if (cx, cy, cz) in gg: # nope, we been here before continue return (cx, cy, cz) else: return (None, None, None) return False goal = self.findpath(__goalcheck_newcheck) for x in range(0, min(len(goal), 15)): dprint('goal', goal[x][1]) history = goal[x][0] tx, ty, tz = goal[x][1] endzonename = history[-1][0] endroomname = history[-1][1] line = [] # drop the first node for zonename, roomname, action in history: line.append('%s->' % action) # figure out which moves have never been made goalroom = self.batmap[endzonename][endroomname] havedonemoves = set() for zoneandroom, move in goalroom['backward']: havedonemoves.add(move) for zoneandroom, move in goalroom['forward']: havedonemoves.add(move) sub = [] for move in goalroom['moves']: if move not in havedonemoves: if tx is not None and move in self.amap: ggoff = self.amap[move] cx = tx + ggoff[0] cy = ty + ggoff[1] cz = tz + ggoff[2] if (cx, cy, cz) in gg: # nope, we been here before continue sub.append(move) if len(sub) > 0: line.append('\x1b#9999ddm[%s]' % '|'.join(sub)) line = bytes(''.join(line), 'utf8') self.game.pushevent('lineunknown', b' \x1b#99ff99m->' + line) return (True, True)
def findpath(self, goalcheck, usegg=True): """This will find all paths that satisfy the goal check function provided. This will find all paths that satisfy the goal check function provided. goalcheck - shall be a function taking the appropriate arguments usegg - uses geometric grid to determine if rooms have been visited """ if self.lastbatmapper is None: self.game.pushevent( 'lineunknown', b'mapper: not inside zone - assuming your in the world (try moving)!' ) return [] thiszone = self.lastbatmapper[0] zone = self.batmap[thiszone] thisxid = self.lastbatmapper[1] goal = [] visited = set() gg = set() gg = {} gg[(0, 0, 0)] = (thiszone, thisxid) bugs = [] bugs.append( (thiszone, thisxid, [(thiszone, thisxid, 'start')], 0, 0, 0)) amap = self.amap if goalcheck is not None: res = goalcheck(thiszone, thisxid, gg, (0, 0, 0)) if res is not False and res is not None: goal.append(([(thiszone, thisxid, 'start')], res)) visited.add((thiszone, thisxid)) while len(bugs) > 0: _bugs = [] # iterate through parents letting them create child bugs for thiszone, thisxid, history, tx, ty, tz in bugs: zone = self.batmap[thiszone] room = zone[thisxid] forward = room['forward'] backward = room['backward'] _combined = set() for action in forward: _combined.add(action) for action in backward: _combined.add(action) for action in _combined: tozone, toxid = action[0] if (tozone, toxid) in visited: # if we been here before dont go back to it continue tomove = action[1] # create new child bug that inherits parent history nhistory = history + [(tozone, toxid, tomove)] if tx is not None and tomove in amap: ggoff = amap[tomove] cx = tx + ggoff[0] cy = ty + ggoff[1] cz = tz + ggoff[2] if (cx, cy, cz) in gg: # it seems most dungeons do not have a straight forward # geometric grid representation for vertical layers which # means this fails to eliminate all visited rooms.. so we # just have to be aware of it pass gg[(cx, cy, cz)] = (tozone, toxid) else: cx = None cy = None cz = None dprint('LOST GEO GRID with %s:%s' % (tx, tomove)) _bugs.append((tozone, toxid, nhistory, cx, cy, cz)) if goalcheck is not None: res = goalcheck(tozone, toxid, gg, (cx, cy, cz)) if res is not False and res is not None: goal.append((nhistory, res)) visited.add((tozone, toxid)) # parent die and children become parents bugs = _bugs self.game.pushevent( 'lineunknown', bytes( ' Searched %s/%s/%s Rooms' % (len(visited), len(zone), len(gg)), 'utf8')) # should have zero or more goals if goalcheck is None: return gg else: return goal
def event_blockunknown(self, event, block): #b:b'\x1b<10spec_skill\x1b|The final estimation is that Caretaker of the Temple can easily reduce you to\r\nminced meat, so run for your life.\r\n\x1b>10' #b:b'\x1b<10spec_skill\x1b|The final estimation is that Monarch butterfly looks quite skilled, beware.\r\n\x1b>10' #b:b"\x1b<10spec_skill\x1b|The final estimation is that Warthog's power overwhelms your mind! You PANIC!!\r\n\x1b>10" if block.find(b'\x1b<10spec_skill\x1b|The final estimation is that') == 0: i = block.find(b'that') + 5 x = findmulti(block, (b'can', b'looks', b'power', b'and', b'has'), i) mob_basename = block[i:x].strip() desc = block[x:] if mob_basename.endswith(b'\'s'): mob_basename = mob_basename[0:-2] mob_basename = mob_basename.decode('utf8') desc = desc.decode('utf8') if desc.find('\r') > -1: desc = desc[0:desc.find('\r')].strip() print('mob_basename:[%s] desc:[%s]' % (mob_basename, desc)) if self.consider_intercept: entry = self.pendingconsiders.pop(0) self.moblore['descnametoname'][entry[1]] = mob_basename else: entry = None mylevel = self.playerlevel # if we do not have our level then the consideration # can be quite meaningless really... right? if mylevel > -1: if mylevel not in self.moblore['consider-base']: self.moblore['consider-base'][mylevel] = {} if mylevel not in self.moblore['consider-full']: self.moblore['consider-full'][mylevel] = {} self.moblore['consider-base'][mylevel][mob_basename] = desc if entry is not None: self.moblore['consider-full'][mylevel][entry[1]] = desc self.game.pushevent('lineunknown', b'\x1b#99ff99mAdded level of [' + bytes(mob_basename, 'utf8') + b'] to MOB-LORE.') self.dumplore() if self.consider_intercept: self.consider_intercept = False # remove everything else to keep from just wasting # bandwidth and time trying them when we have already # found the correct one _pendingconsiders = [] for p in self.pendingconsiders: if p[1] != entry[1]: _pendingconsiders.append(p) self.pendingconsiders = _pendingconsiders self.pendinglooks.append(mob_basename) self.do_nextconsider() return True else: # take a quick look at the mob dprint('doing quick look at [%s]' % mob_basename) self.game.lockcmdgroup(self) self.pendinglooks.append(mob_basename) self.do_nextlook() elif block.find(b'\x1b<10spec_skill') == 0 and self.consider_intercept: # drop it return True
def processline(self, line, fgdef = None, bgdef = None): """Add line but convert terminal codes into HTML and convert from bytes to string. """ # convert to string and replace any crazy characters line = line.decode('utf8', 'ignore') line = line.replace('\\', '\\\\') # escape any quotes because we encode this string into # javascript call and unescaped quotes will screw it up line = line.replace('"', '\\"') line = line.replace('<', '<') line = line.replace('>', '>') line = line.replace('-', '<nobr>-</nobr>') line = line.replace('\t', '	') line = line.replace(' ', ' ') # split it to handle terminal escape codes parts = line.split('\x1b') line = [] fgdef = fgdef or self.fgcolor bgdef = bgdef or self.bgcolor line.append('<span class=\\"%s %s\\">%s</span>' % (fgdef, bgdef, parts[0])) for x in range(1, len(parts)): part = parts[x] if part[0] == '#': hexcolor = part[1:part.find('m')] hexcolor = hexcolortotuple(hexcolor) hexcolor = hexcolordimblue(hexcolor, 0.4) #hexcolor = hexcolordimer(hexcolor, 1.0, 1.0, 0.6) hexcolor = tupletohexcolor(hexcolor) rmsg = part[part.find('m') + 1:] rmsg = rmsg.replace(' ', ' ' * 3) rmsg = rmsg.replace(' ', ' ') line.append('<span style=\\"color: #%s;\\">%s</span>' % (hexcolor, rmsg)) #line.append(rmsg) continue if part[0] != '[': print('Expected [!') cstr = part[1:part.find('m')] rmsg = part[part.find('m') + 1:] codes = cstr.split(';') if len(cstr) < 1: self.fgcolor = self.nfgcolor self.bgcolor = self.nbgcolor for code in codes: if len(code) < 1: continue if code == '0': self.fgcolor = self.nfgcolor self.bgcolor = self.nbgcolor self.fgbright = False continue if code == '1': self.fgbright = True continue if code == '2': self.fgbright = False continue if code[0] == '3': val = code[1] if val in self.colormap: if self.fgbright: self.fgcolor = 'hc_bfg_%s' % self.colormap[val] else: self.fgcolor = 'hc_fg_%s' % self.colormap[val] continue if code[0] == '4': if code[1] in self.colormap: self.bgcolor = 'hc_bg_' % self.colormap[code[1]] continue dprint('ignored code [%s]' % code) line.append('<span class=\\"%s %s\\">%s</span>' % (self.fgcolor, self.bgcolor, rmsg)) line = ''.join(line) return line