class CogToRoguebox: ''' Contains a roguelike game, and offers controls. The roguelike itself is contained to a 23x23 box in the top-left sector. Logging is offered in a box next to that. ''' def __init__(self, cog_h, engine, orb): self.cog_h = cog_h self.engine = engine self.orb = orb # self.track_prime_console = orb.track(TrackPrimeConsole) self.track_containment_mode = orb.track(TrackContainmentMode) # self.rail_roguebox = RailRoguebox() self.rail_message_feed = RailMessageFeed() self.cgrid_last = None self.cgrid_next = None self.d_keycode_to_directive = {} self.d_control_scheme = {} # (control_scheme_h, directive_h) = keycode # self.b_game_started = False self.b_mail_waiting = False self.b_refresh_needed = False def orb_turn(self, activity): if None == self.rail_roguebox: return if not self.track_containment_mode.is_focus_on_game(): return if self.b_mail_waiting: activity.mark( l=self, s='mail processing') for message in self.rail_roguebox.retrieve_mail(): self.rail_message_feed.accept( message=message, turn=self.rail_roguebox.get_turn()) self.b_mail_waiting = False self.b_refresh_needed = True # if self.b_refresh_needed: self._diff_display_refresh() self.b_refresh_needed = False # def on_init(self): console_height = self.track_prime_console.height console_width = self.track_prime_console.width # if console_height < ROGUEBOX_GAMEBOX_HEIGHT: raise Exception("console height %s too small for game height %s."%( console_height, ROGUEBOX_GAMEBOX_HEIGHT)) if console_width < ROGUEBOX_GAMEBOX_WIDTH: raise Exception("console width %s too small for game width %s."%( console_width, ROGUEBOX_GAMEBOX_WIDTH)) # rail_h = '%s/roguebox'%(self.cog_h) self.rail_roguebox.zero( rail_h=rail_h, engine=self.engine, grid_height=ROGUEBOX_GAMEBOX_HEIGHT, grid_width=ROGUEBOX_GAMEBOX_WIDTH, cb_ready_alert=self._rl_ready_alert, cb_grid_alert=self._rl_grid_alert, cb_mail_alert=self._rl_mail_alert, cb_over_alert=self._rl_over_alert) # rail_h = '%s/message_feed'%(self.cog_h) self.rail_message_feed.zero( rail_h=rail_h, height=ROGUEBOX_MFEED_HEIGHT, width=ROGUEBOX_MFEED_WIDTH, cpair_new=solent_cpair('teal'), cpair_old=solent_cpair('blue')) self.cgrid_last = Cgrid( width=console_width, height=console_height) self.cgrid_next = Cgrid( width=console_width, height=console_height) # # sequence the possible directives in the game to the core. this will # give this outer core the opportunity to match directives it # recognises to keycodes. in the future, you could imagine being able # to configure user keystrokes using this data. for directive in self.rail_roguebox.get_supported_directives(): self.nearcast.directive( directive_h=directive.h, description=directive.description) def on_keycode_to_directive(self, control_scheme_h, keycode, directive_h): self.d_keycode_to_directive[keycode] = directive_h self.d_control_scheme[ (control_scheme_h, directive_h) ] = keycode def on_x_game_ready(self): self.b_game_started = True self.nearcast.o_game_focus() def on_o_game_new(self): self.rail_message_feed.clear() self.rail_roguebox.new_game() def on_x_game_mail(self): self.b_mail_waiting = True def on_x_game_grid(self): self.b_refresh_needed = True def on_game_input(self, keycode): if keycode not in self.d_keycode_to_directive: return directive_h = self.d_keycode_to_directive[keycode] self.rail_roguebox.directive( directive_h=directive_h) self.rail_message_feed.scroll_past( turn=self.rail_roguebox.get_turn()-3) self.b_refresh_needed = True def on_o_game_focus(self): if not self.b_game_started: self.nearcast.menu_focus() return self._full_display_refresh() # def _rl_ready_alert(self): self.nearcast.x_game_ready() def _rl_grid_alert(self): self.nearcast.x_game_grid() def _rl_mail_alert(self): self.nearcast.x_game_mail() def _rl_over_alert(self): self.nearcast.x_game_over() # def _full_display_refresh(self): self.nearcast.term_clear() self.cgrid_last.clear() self._diff_display_refresh() def _diff_display_refresh(self): self.rail_roguebox.get_cgrid( cgrid=self.cgrid_next, nail=ROGUEBOX_GAMEBOX_NAIL, peri=ROGUEBOX_GAMEBOX_PERI) for idx, message in enumerate(self.rail_message_feed.list_messages()): self.cgrid_next.put( drop=idx, rest=0, s=message, cpair=solent_cpair('white')) # for drop in range(self.track_prime_console.height): for rest in range(self.track_prime_console.width): (old_c, old_cpair) = self.cgrid_last.get( drop=drop, rest=rest) (c, cpair) = self.cgrid_next.get( drop=drop, rest=rest) if c == old_c and cpair == old_cpair: continue self.nearcast.term_write( drop=drop, rest=rest, s=c, cpair=cpair) # self.cgrid_last.blit( src_cgrid=self.cgrid_next)
class SpinSelectionUi: def __init__(self, spin_h, engine, console_type, cb_selui_keycode, cb_selui_lselect): self.spin_h = spin_h self.engine = engine self.console_type = console_type self.cb_selui_keycode = cb_selui_keycode self.cb_selui_lselect = cb_selui_lselect # self.cs_selui_keycode = CsSeluiKeycode() self.cs_selui_lselect = CsSeluiLselect() # self.width = None self.height = None self.cgrid = None self.mode = MODE_NONE self.console = None self.select_cursor_on = True self.select_cursor_t100 = time.time() * 100 self.select_drop = 0 self.select_rest = 0 self.select_cgrid = None # self.lmousedown_coords = None # def eng_turn(self, activity): if self.mode == MODE_NONE: return # keycode = self.console.async_get_keycode() if keycode: activity.mark(l=self, s='received keystroke %s' % keycode) if keycode == solent_keycode('lmousedown'): self.lmousedown_coords = self.console.get_last_lmousedown() elif keycode == solent_keycode('lmouseup'): self.lmouseup_coords = self.console.get_last_lmouseup() elif keycode == solent_keycode('rmousedown'): self.rmousedown_coords = self.console.get_last_rmousedown() elif keycode == solent_keycode('rmouseup'): self.rmouseup_coords = self.console.get_last_rmouseup() self.accept_key(keycode=keycode) # self.refresh_console() def eng_close(self): if None != self.console: self.console.close() # def open_console(self, width, height): self.width = width self.height = height self.cgrid = Cgrid(width=width, height=height) self.select_cgrid = Cgrid(width=width, height=height) self.console = Console(console_type=self.console_type, width=width, height=height) self.mode = MODE_STANDARD def close_console(self): if not self.console: return self.console.close() self.mode = MODE_NONE self.select_drop = 0 self.select_rest = 0 def to_mode_standard(self): if None == self.console: raise Exception("No console open") self.mode = MODE_STANDARD def to_mode_select(self): if None == self.console: raise Exception("No console open") self.mode = MODE_SELECT self.select_cursor_on = True self.select_cursor_t100 = time.time() * 100 def scroll(self): self.cgrid.scroll() def clear(self): self.cgrid.clear() def write(self, drop, rest, s, cpair): self.cgrid.put(drop=drop, rest=rest, s=s, cpair=cpair) def accept_key(self, keycode): ''' By making this an exposed command, we can allow the console to be used as a display with input coming from elsewhere. ''' if self.mode == MODE_SELECT: if keycode == solent_keycode('esc'): self.to_mode_standard() elif keycode in (solent_keycode('newline'), solent_keycode('s')): (c, cpair) = self.cgrid.get(drop=self.select_drop, rest=self.select_rest) self._call_selui_lselect(drop=self.select_drop, rest=self.select_rest, c=c, cpair=cpair) self.to_mode_standard() else: # we let the user navigate the cursor using arrow keys, vi # keys, gollop keys. b_moved = False # standard navigation if keycode in (solent_keycode('q'), solent_keycode('a'), solent_keycode('z'), solent_keycode('y'), solent_keycode('h'), solent_keycode('b')): if self.select_rest > 0: self.select_rest -= 1 b_moved = True if keycode in (solent_keycode('e'), solent_keycode('d'), solent_keycode('c'), solent_keycode('u'), solent_keycode('l'), solent_keycode('n')): if self.select_rest < self.width - 1: self.select_rest += 1 b_moved = True if keycode in (solent_keycode('q'), solent_keycode('w'), solent_keycode('e'), solent_keycode('y'), solent_keycode('k'), solent_keycode('u')): if self.select_drop > 0: self.select_drop -= 1 b_moved = True if keycode in (solent_keycode('z'), solent_keycode('x'), solent_keycode('c'), solent_keycode('b'), solent_keycode('j'), solent_keycode('n')): if self.select_drop < self.height - 1: self.select_drop += 1 b_moved = True # shift navigation if keycode in (solent_keycode('Q'), solent_keycode('A'), solent_keycode('Z'), solent_keycode('Y'), solent_keycode('H'), solent_keycode('B')): self.select_rest = 0 b_moved = True if keycode in (solent_keycode('E'), solent_keycode('D'), solent_keycode('C'), solent_keycode('U'), solent_keycode('L'), solent_keycode('N')): self.select_rest = self.width - 1 b_moved = True if keycode in (solent_keycode('Q'), solent_keycode('W'), solent_keycode('E'), solent_keycode('Y'), solent_keycode('K'), solent_keycode('U')): self.select_drop = 0 b_moved = True if keycode in (solent_keycode('Z'), solent_keycode('X'), solent_keycode('C'), solent_keycode('B'), solent_keycode('J'), solent_keycode('N')): self.select_drop = self.height - 1 b_moved = True # if b_moved: self.select_cursor_on = True self.select_cursor_t100 = time.time() * 100 elif self.mode == MODE_STANDARD: if keycode == solent_keycode('esc'): self.to_mode_select() else: if keycode == solent_keycode('lmouseup'): # We check to see that the coords were the same as # when the mouse was depressed. If they weren't, this # usually implies the user has rethought their # decision, and we abort. From memory, this is how FTL # works, and it's super-useful. (ddrop, drest) = self.lmousedown_coords (udrop, urest) = self.lmouseup_coords if (ddrop, drest) == (udrop, urest): (c, cpair) = self.cgrid.get(drop=udrop, rest=urest) self._call_selui_lselect(drop=udrop, rest=urest, c=c, cpair=cpair) elif keycode in MOUSE_EVENTS: pass else: # we pass the keystroke back in a callback self._call_selui_keycode(keycode=keycode) def refresh_console(self): if self.mode == MODE_NONE: pass elif self.mode == MODE_SELECT: # cursor flipping t100 = time.time() * 100 if t100 - self.select_cursor_t100 > 53: self.select_cursor_t100 = t100 if self.select_cursor_on: self.select_cursor_on = False else: self.select_cursor_on = True # cursor display self.select_cgrid.blit(src_cgrid=self.cgrid) if self.select_cursor_on: self.select_cgrid.put(drop=self.select_drop, rest=self.select_rest, s='@', cpair=solent_cpair('red')) self.console.screen_update(cgrid=self.select_cgrid) elif self.mode == MODE_STANDARD: self.console.screen_update(cgrid=self.cgrid) # def _call_selui_keycode(self, keycode): self.cs_selui_keycode.keycode = keycode self.cb_selui_keycode(cs_selui_keycode=self.cs_selui_keycode) def _call_selui_lselect(self, drop, rest, c, cpair): self.cs_selui_lselect.drop = drop self.cs_selui_lselect.rest = rest self.cs_selui_lselect.c = c self.cs_selui_lselect.cpair = cpair self.cb_selui_lselect(cs_selui_lselect=self.cs_selui_lselect)