From: David Sharpe Date: Sat, 17 May 2014 21:48:59 +0000 (+0200) Subject: Merge branch 'master' of git://ctpug.org.za/naja X-Git-Tag: 0.1~15 X-Git-Url: https://git.ctpug.org.za/?p=naja.git;a=commitdiff_plain;h=d26dffb73ba125fc76931375365b10060cf5d892;hp=4bc519aed28267ba4e336e9cb81948a5d6533c34 Merge branch 'master' of git://ctpug.org.za/naja --- diff --git a/data/location_decks/introduction.yaml b/data/location_decks/introduction.yaml index e1011f0..89a67fe 100644 --- a/data/location_decks/introduction.yaml +++ b/data/location_decks/introduction.yaml @@ -19,7 +19,7 @@ _action_definitions: action_class: 'DoNothing' required_bits: [] data: - message: "Welcome to the game. You can only move to chequered squares, therefore you can stay here or move right." + message: "Welcome to the tutorial!\nYou can select any tile, but only move in directions with bits set. These are checquered. Now, only the current tile and 1 tile {EAST}.\nSelect {EAST} tile and press {RETURN}." - &STEP1-CARD card_name: 'step1' @@ -32,17 +32,24 @@ _action_definitions: data: message: "Moving to a tile requires picking an action. Some tiles' actions set bits on your robot. Such as the {SOUTH} bit." + - &STEP2-ACTION-NULL + action_class: 'SetBits' + required_bits: [] + data: + message: "So does this one. See, we gave you a choice!" + - &STEP2-CARD card_name: 'step2' bits: [SOUTH] actions: - *STEP2-ACTION + - *STEP2-ACTION-NULL - &STEP3-ACTION action_class: 'ClearBits' required_bits: [] data: - message: "Other tiles' actions clear bits. {SOUTH} or {EAST}. For the next part of the tutorial, we are going to strictly control your movement bits." + message: "Other tiles' actions clear bits. This will clear {SOUTH} or {EAST}.\nFor the next part of the tutorial, we are going to control your movement bits strictly, so you don't get lost." - &STEP3-CARD-1 card_name: 'step3-1' @@ -60,7 +67,7 @@ _action_definitions: action_class: 'SetBits' required_bits: [] data: - message: "There are key bits that can be set, such as {RED}. They may be required by actions. This action also sets some movement bits." + message: "There are key bits that can be set, such as {RED}. They may be required by actions.\nThis action also sets {EAST,SOUTH}." - &STEP4-CARD card_name: 'step4' @@ -72,7 +79,7 @@ _action_definitions: action_class: 'GenericBits' required_bits: [BLUE] data: - message: "You need to have the {BLUE} bit, to use this action and continue. Some actions have more complex requirements." + message: "You need to have the {BLUE} bit to use this action and continue.\nSome actions have more complex requirements." set: [EAST] clear: [NORTH, SOUTH, WEST] @@ -80,7 +87,7 @@ _action_definitions: action_class: 'GenericBits' required_bits: [] data: - message: "Go back. Set {WEST}. Clear {NORTH,SOUTH,EAST}." + message: "Go back.\nSet {WEST}. Clear {NORTH,SOUTH,EAST}." set: [WEST] clear: [EAST, SOUTH, NORTH] @@ -95,7 +102,7 @@ _action_definitions: action_class: 'GenericBits' required_bits: [RED] data: - message: "You need to have the {RED} bit, to use this action to set the {BLUE} bit." + message: "You need to have the {RED} bit to use this action to set the {BLUE} bit." set: [NORTH, BLUE] clear: [SOUTH, EAST, WEST] @@ -103,7 +110,7 @@ _action_definitions: action_class: 'GenericBits' required_bits: [] data: - message: "This action doesn't require anything. Go back. Set {NORTH}. Clear {SOUTH,EAST,WEST}." + message: "This action doesn't require anything. Go back.\nSet {NORTH}. Clear {SOUTH,EAST,WEST}." set: [NORTH] clear: [SOUTH, EAST, WEST] @@ -118,7 +125,7 @@ _action_definitions: action_class: 'SetBits' required_bits: [] data: - message: "Almost there. You have free reign on this column. Collect yourself a win bit {WINTOKEN} to finish the level. Good luck!" + message: "Almost there. You have free rein in this column.\nFinish the game by collecting enough {WINTOKEN}. 1 in this level.\nGood luck!" - &STEP7-CARD card_name: 'step7' @@ -160,7 +167,7 @@ _action_definitions: required_bits: [GREEN] data: direction: EAST - message: "Some actions change the game board." + message: "All of the actions on this tile require {GREEN}. Without it, you can't even enter.\nActions like this one change the game board." - &STEP10-CARD card_name: 'step10' @@ -171,7 +178,7 @@ _action_definitions: action_class: 'GenericBits' required_bits: [] data: - message: "We may have lied to you. Set {WEST}. Clear {NORTH,SOUTH,EAST}." + message: "We may have lied to you about restricting to this column.\nSet {WEST}. Clear {NORTH,SOUTH,EAST}." set: [WEST] clear: [NORTH, SOUTH, EAST] @@ -185,7 +192,7 @@ _action_definitions: action_class: 'GenericBits' required_bits: [] data: - message: "In this board, tiles didn't change. In the random games, after taking an action (or the timer expires) the tile will be replaced by another one. Set {NORTH}. Clear {SOUTH,EAST,WEST}." + message: "In this board, tiles didn't change. In the random games, after taking an action (or a timer expires) the tile will be replaced.\nSet {NORTH}. Clear {SOUTH,EAST,WEST}." set: [NORTH] clear: [SOUTH, EAST, WEST] diff --git a/naja/scenes/credits.py b/naja/scenes/credits.py index 75f1b3c..a522c98 100644 --- a/naja/scenes/credits.py +++ b/naja/scenes/credits.py @@ -35,10 +35,16 @@ class CreditsScene(Scene): u'Adrianna Pińska, David Sharpe, Jeremy Thurgood, ' u'Neil Muller, Simon Cross & Stefano Rivera', '', + 'Special thanks to:', + '', + 'Desilu Crossman', + 'for snacks and tutorial inspiration', + '', 'Music by Rolemusic:', 'http://rolemusic.sawsquarenoise.com/', '', - 'Press ESC to return to the menu.', + 'Out of credits. Insert coin.', + '(Press ESC to return to the menu.)', ]), colour='white', padding=1, bg_colour=(0, 0, 0, 0), centre=True, diff --git a/naja/scenes/dummygame.py b/naja/scenes/dummygame.py new file mode 100644 index 0000000..5111d05 --- /dev/null +++ b/naja/scenes/dummygame.py @@ -0,0 +1,40 @@ +""" +Dummy scene that overlays a static rendering of a a game scene +""" + +import pygame.locals as pgl +import pygame + +from naja.constants import KEYS, PALETTE, SCREEN +from naja.events import SceneChangeEvent, LoadGameEvent +from naja.sound import sound +from naja.scenes.scene import Scene +from naja.scenes.game import GameScene +from naja.gamestate import GameState +from naja.widgets.image_box import PreRenderedImageBox +from naja.widgets.text import TextWidget, TextBoxWidget + + +class DummyGameScene(Scene): + + def __init__(self, state=None): + super(DummyGameScene, self).__init__(state) + if not state: + game_state = GameState.new(max_health=4, wins_required=4) + else: + game_state = state + game = GameScene(game_state, play_sound=False) + game_surface = pygame.surface.Surface(SCREEN) + game.render(game_surface) + # Force tiles past the animation stage + game.board_widget.force_skip_animation() + game.render(game_surface) + self.add(PreRenderedImageBox((0, 0), game_surface)) + + def handle_scene_event(self, ev): + from naja.scenes.menu import MenuScene + if ev.type == pgl.KEYDOWN and ev.key in KEYS.QUIT: + # drop current state + LoadGameEvent.post(None) + SceneChangeEvent.post(MenuScene) + return diff --git a/naja/scenes/game.py b/naja/scenes/game.py index c0b4b27..82e08db 100644 --- a/naja/scenes/game.py +++ b/naja/scenes/game.py @@ -22,17 +22,19 @@ class GameScene(Scene): Gameboard scene. """ - def __init__(self, state): + def __init__(self, state, play_sound=True): super(GameScene, self).__init__(state) self.add(PlayerBitsWidget((0, 0), state)) info = InfoAreaWidget((480, 0), state) - self.add(BoardWidget((0, 60), state, info)) + self.board_widget = BoardWidget((0, 60), state, info) + self.add(self.board_widget) self.add(GameBitsWidget((0, 540), state)) self.add(info) self.add(RobotWidget(state)) - sound.play_sound('startup.ogg') - background_track = random.choice(TUNES) - sound.play_music(background_track, 0.25) + if play_sound: + sound.play_sound('startup.ogg') + background_track = random.choice(TUNES) + sound.play_music(background_track, 0.25) def handle_scene_event(self, ev): from naja.scenes.menu import MenuScene diff --git a/naja/widgets/board.py b/naja/widgets/board.py index 32fb5af..b2a93fa 100644 --- a/naja/widgets/board.py +++ b/naja/widgets/board.py @@ -62,6 +62,10 @@ class BoardWidget(Widget): idx = 0 self.update_card_pos(moves[idx]) + def force_skip_animation(self): + for tile in self._tiles: + tile.animation = 0 + def handle_event(self, ev): if self.state.gameboard.player_mode == ACT: return super(BoardWidget, self).handle_event(ev) diff --git a/naja/widgets/image_box.py b/naja/widgets/image_box.py index 32787df..e9b4bf3 100644 --- a/naja/widgets/image_box.py +++ b/naja/widgets/image_box.py @@ -22,3 +22,18 @@ class ImageBox(Widget): def draw(self, surface): surface.blit(self.surface, self.rect) + + +class PreRenderedImageBox(Widget): + """Hold an image given as a surface""" + + def __init__(self, pos, image): + super(PreRenderedImageBox, self).__init__(pos) + self.surface = image.copy() + + def prepare(self): + self.size = self.surface.get_rect().size + + def draw(self, surface): + surface.blit(self.surface, self.rect) + diff --git a/naja/widgets/info_area.py b/naja/widgets/info_area.py index 97c3daa..1ff6bbb 100644 --- a/naja/widgets/info_area.py +++ b/naja/widgets/info_area.py @@ -57,24 +57,21 @@ class InfoAreaWidget(Widget): y_offset = 0 pos = lambda: (INFO_LEFT_PADDING, y_offset) - # Top title - title = TextWidget( - pos(), TITLES[self.state.gameboard.player_mode], - colour=PALETTE.WHITE) - title.render(self.surface) - y_offset += title.surface.get_rect().height - 4 - # Bits + y_offset += 12 bits_text = ''.join('1' if bit in self.card.bitwise_operand else '0' for bit in reversed(range(8))) if self.card.bitwise_operand: bits_text = '%s %s' % ( bits_text, bit_glyphs(self.card.bitwise_operand)) card_bits = TextBoxWidget( - pos(), bits_text, box_width=box_width, - colour=PALETTE.LIGHT_TURQUOISE, bg_colour=PALETTE.BLACK) - card_bits.render(self.surface) - y_offset += card_bits.surface.get_rect().height + 4 + (0, 0), bits_text, padding=4, centre=True, + colour=PALETTE.WHITE, border=2, + bg_colour=PALETTE.BLACK, border_colour=PALETTE.BLUE, + box_width=box_width) + card_bits.prepare() + self.surface.blit(card_bits.surface, pos()) + y_offset += card_bits.surface.get_rect().height + 12 # Actions for choice, action in enumerate(self.card.actions): @@ -119,7 +116,7 @@ class InfoAreaWidget(Widget): def prepare_action(self, choice, action, y_offset, box_width): x_offset = INFO_LEFT_PADDING - glyphs_x_offset = 0 + glyphs_x_offset = 2 glyphs_y_offset = y_offset y_offset += ACTION_TEXT_OFFSET action_viable = action.check_available(self.state.player) diff --git a/naja/widgets/text.py b/naja/widgets/text.py index 5dac4e6..af7f0ac 100644 --- a/naja/widgets/text.py +++ b/naja/widgets/text.py @@ -149,24 +149,25 @@ class TextBoxWidget(TextWidget): super(TextBoxWidget, self).__init__(*args, **kwargs) - def lines(self, image_map): + def lines(self): if self.box_width != 0: - return self._wrapped_lines(image_map) + return self._wrapped_lines() else: - return self.text.splitlines() + return ((line, []) for line in self.text.splitlines()) - def _prepare_glyph(self, image_map, glyph, current_words, lines): + def _prepare_glyph(self, glyph, current_words): + glyphs = [] size = self.font.size(' '.join(current_words[:-1] + [''])) - x = size[0] * EIGHT_BIT_SCALE + self.padding - y = size[1] * lines * EIGHT_BIT_SCALE + self.padding + x = size[0] * EIGHT_BIT_SCALE for glyph_key in glyph.glyph_keys: image_name, colour = MARKUP_MAP[glyph_key] if colour is None: colour = self.colour image = resources.get_image( image_name, transforms=(EIGHT_BIT, blender(colour))) - image_map[(x, y)] = image + glyphs.append(((x, 0), image)) x += image.get_width() + return glyphs def _check_markup(self, word): suffix = '' @@ -183,7 +184,7 @@ class TextBoxWidget(TextWidget): return None - def _wrapped_lines(self, image_map): + def _wrapped_lines(self): def words_fit(words): words_line = ' '.join(words) width = self.font.size(words_line)[0] * EIGHT_BIT_SCALE @@ -198,9 +199,9 @@ class TextBoxWidget(TextWidget): line = line.strip() if not line: line_count += 1 - yield line + yield (line, []) continue - current_words = [] + current_words, glyphs = [], [] remaining_words = line.split() while remaining_words: word = remaining_words.pop(0) @@ -210,30 +211,31 @@ class TextBoxWidget(TextWidget): current_words.append(word) if words_fit(current_words): if glyph is not None: - self._prepare_glyph( - image_map, glyph, current_words, line_count) + glyphs.extend(self._prepare_glyph( + glyph, current_words)) else: line_count += 1 - yield ' '.join(current_words[:-1]) - current_words = [] + yield (' '.join(current_words[:-1]), glyphs) + current_words, glyphs = [], [] if glyph is not None: word = glyph.markup_text remaining_words.insert(0, word) if current_words and words_fit(current_words): line_count += 1 - yield ' '.join(current_words) + yield (' '.join(current_words), glyphs) def prepare(self): self.font = resources.get_font(self.fontname, self.fontsize) - image_map = {} rendered_lines = [] width, height = self.padding * 2, self.padding * 2 - for line in self.lines(image_map): + for line, glyphs in self.lines(): line_surface = self.render_line(line) line_rect = line_surface.get_rect() rendered_lines.append(line_surface) width = max(width, line_rect.width + self.padding * 2) height += line_rect.height + for pos, img in glyphs: + line_surface.blit(img, pos) if self.full_width: width = max(width, self.box_width) @@ -250,7 +252,5 @@ class TextBoxWidget(TextWidget): x += self.padding self.surface.blit(line_surface, (x, y)) y += line_surface.get_rect().height - for pos, img in image_map.items(): - self.surface.blit(img, pos) self.render_border(self.surface)