def __init__(self, root_dir): # Make sure __init__ doesn't do any crazy stuff. # Should always make sure initializing Ohno won't throw any exceptions. self.logger = LogLady( root_dir + "/logs", ( "ohno", "client", "telnet", "framebuffer", "hero", "dungeon", "ui", "curses", "input", "pty", "strategy", "action", "tile", "level", "messages", "event", "monster", "spoilers", "item", ), ) # Every submodule needs to be able to find other submodules, so they # all take an ohno instance as the first argument. self.client = Client(self) self.framebuffer = FrameBuffer(self) self.hero = Hero(self) self.dungeon = Dungeon(self) self.ai = AI(self) self.messages = Messages(self) self.spoilers = Spoilers(self) self.ui = UI(self) self.paused = self.running = None self.last_action = None self.tick = 0 self.all_messages = [] YouDie.subscribe(self.on_youdie) MessageEvent.subscribe(self.on_message)
class Ohno(object): """ The root object. Every subpart of ohno can be found through this class. """ def __init__(self, root_dir): # Make sure __init__ doesn't do any crazy stuff. # Should always make sure initializing Ohno won't throw any exceptions. self.logger = LogLady( root_dir + "/logs", ( "ohno", "client", "telnet", "framebuffer", "hero", "dungeon", "ui", "curses", "input", "pty", "strategy", "action", "tile", "level", "messages", "event", "monster", "spoilers", "item", ), ) # Every submodule needs to be able to find other submodules, so they # all take an ohno instance as the first argument. self.client = Client(self) self.framebuffer = FrameBuffer(self) self.hero = Hero(self) self.dungeon = Dungeon(self) self.ai = AI(self) self.messages = Messages(self) self.spoilers = Spoilers(self) self.ui = UI(self) self.paused = self.running = None self.last_action = None self.tick = 0 self.all_messages = [] YouDie.subscribe(self.on_youdie) MessageEvent.subscribe(self.on_message) def start_resume_game(self): """Starts or resumes a nethack game within the current client.""" self.logger.ohno("Starting/resuming game..") self.client.start_resume_game() def loop(self): """ The main controller of ohno. Makes sure everything happens in the correct order. """ self.running = True self.paused = False first = True while self.running: # First, take input from the client and update our framebuffer. # This should always leave the client in a state where _doing stuff_ # is possible (that is, not in a menu, no --More-- messages, etc.) # Any messages sent to us is stored in `messages` temporarily, # because we want to update the hero and dungeon before sending them # to ohno.messages. messages = self.framebuffer.update() self.all_messages.extend(messages) # framebuffer.update() might shut us down if we're dead. if not self.running: break # Updates stats (bottomlines) and hero's position. self.hero.update() # Creates new level and/or updates the level with what we got from # framebuffer. self.dungeon.update() # Update ohno about the current game (inventory, discoveries, etc.) # the first pass through this loop. if first: first = False messages += self.look() self.discoveries() # Start parsing the messages for message in messages: if message: self.messages.parse_message(message) # Update the user display and/or take input from the user. self.ui.update() # Some actions might want to do something depending on the outcome # of an action (example: what happened when I read the unidentified # scroll?). This could be used for sanity checks aswell. if self.last_action: self.last_action.done(messages) # Ask the AI for the next action and send the key strokes needed for # that action. self.logger.ohno("Getting the next action from `strategy`..") action = self.ai.strategy.next_action() command = action.get_command() self.logger.ohno("Got action: %r (%r)!" % (action, command)) self.client.send(command) while self.running and self.paused: time.sleep(0.01) self.ui.update() # Internal tick used by ai.pathing as a sanity check. self.tick += 1 self.last_action = action def shutdown(self): """ Shuts ohno down without saving. You should probably use .save() instead. """ self.ui.shutdown() # Curses self.running = False def save(self): """Tries to save the game and then runs .shutdown()""" self.client.send("\x1b\x1b\x1b\x1bSyq") self.shutdown() # actions def farlook(self, to_tile): from_tile = self.dungeon.curtile x1, y1 = from_tile.idx % 80, from_tile.idx / 80 x2, y2 = to_tile.idx % 80, to_tile.idx / 80 sequence = util.farlook(x1, y1, x2, y2) self.client.send(";%s." % sequence) messages = self.framebuffer.update() assert len(messages) == 2 return messages[1] def discoveries(self): self.client.send("\\") self.framebuffer.update() def look(self): self.client.send(":") return self.framebuffer.update() # events def on_youdie(self, event): self.logger.ohno("Seems like we're dead. Shutting down.") self.shutdown() print "\n".join(event.messages) print "I died. Sorry!" exit(0) def on_message(self, event): if event.msgtype == "you_see_here": thing = event.kwargs["item"] FoundItems.fire(self, [thing])