예제 #1
0
파일: weeds.py 프로젝트: solent-eng/solent
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)
예제 #2
0
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)