From 82c0cb378c56692f3d5758df9ad59e9e5cd089b4 Mon Sep 17 00:00:00 2001 From: Mat Booth Date: Sat, 24 Nov 2018 12:04:57 +0000 Subject: [PATCH] Settlers of EMF UI improvements: Always use menu button to summon a menu screen, add a status line that gives hints about controls etc, allow using the B button as a shortcut for "Back" in menus that have such an option Also add a kind of "cheat mode" for testing that grants extra resources --- settlers_of_emf/main.py | 87 ++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/settlers_of_emf/main.py b/settlers_of_emf/main.py index 25eb8d0..7954355 100644 --- a/settlers_of_emf/main.py +++ b/settlers_of_emf/main.py @@ -42,6 +42,11 @@ ORE = {'kind':4, 'col': ugfx.html_color(0x757575)} DESERT = {'kind':5, 'col': ugfx.html_color(0xffee55)} # Not really a resource RESOURCE_KINDS = [ SHEEP, WHEAT, WOOD, BRICK, ORE ] +# Set this to true to enable a "cheat code" to get more resources for testing +# When in the main game running state, press 5 five times to get five more of +# every resource +TEST_MODE = False + class State: @@ -89,6 +94,7 @@ class Menu(State): self.menu_offset = 120 else: self.menu_offset = 100 + self.back = -1 def is_choice_enabled(self, num): c = self.choices[num] @@ -129,7 +135,11 @@ class Menu(State): if len(self.choices) == 1: text = "{} ".format(c['name']) else: - text = "{} - {} ".format(i + 1, c['name']) + if c['name'] == "Back": + text = "B - {} ".format(c['name']) + self.back = i + else: + text = "{} - {} ".format(i + 1, c['name']) ugfx.text(18, offset + self.menu_offset, text, col) if 'cost' in c: for j in range(len(c['cost'])): @@ -147,6 +157,7 @@ class Menu(State): def initialise(self): # Register callbacks Buttons.enable_interrupt(Buttons.BTN_A, self._button_callback) + Buttons.enable_interrupt(Buttons.BTN_B, self._button_callback) Buttons.enable_interrupt(Buttons.JOY_Up, self._button_callback) Buttons.enable_interrupt(Buttons.JOY_Down, self._button_callback) for i in range(len(self.choices)): @@ -156,6 +167,7 @@ class Menu(State): def deinitialise(self): # Unregister callbacks Buttons.disable_interrupt(Buttons.BTN_A) + Buttons.disable_interrupt(Buttons.BTN_B) Buttons.disable_interrupt(Buttons.JOY_Up) Buttons.disable_interrupt(Buttons.JOY_Down) for i in range(len(self.choices)): @@ -165,6 +177,10 @@ class Menu(State): def _button_callback(self, btn): if btn == Buttons.BTN_A: self.done = True + elif btn == Buttons.BTN_B: + if self.back > -1: + self._set_selection(self.back) + self.done = True else: if btn == Buttons.JOY_Up: new_selection = self._prev_valid_selection(self.selection) @@ -283,13 +299,15 @@ class ActionMenu(Menu): {'name': "Build"}, {'name': "Trade"}, {'name': "End Turn"}, + {'name': "Exit Game"}, {'name': "Back"}, ] BUILD = 0 TRADE = 1 END_TURN = 2 - BACK = 3 + EXIT_GAME = 3 + BACK = 4 def __init__(self, dice_roll, clear_title=True): # Rolling the dice is mandatory, so don't let the turn end unless it happened @@ -607,6 +625,13 @@ class Resource(): class Player: """The player's hand of resource cards and their score and what not.""" + STATUS_ACTIONS_DICE = "menu = actions / # = roll dice " + STATUS_ACTIONS = "menu = actions " + STATUS_MOVE_ROBBER = "Move the robber! " + STATUS_MUST_MOVE_ROBBER = "Robber MUST be moved! " + STATUS_BUILD = "Select a build location. " + STATUS_NO_BUILD = "No valid build locations. " + def __init__(self, team, roads, settlements): # Player team details self.team = team @@ -623,6 +648,7 @@ class Player: # Turn number self.turn = 0 + self.status = Player.STATUS_ACTIONS_DICE def score(self): points = 0 @@ -632,6 +658,7 @@ class Player: def increment_turn(self): self.turn = self.turn + 1 + self.status = Player.STATUS_ACTIONS_DICE def num_resources(self): """Total number of all resources the player has""" @@ -737,8 +764,13 @@ class Player: ugfx.text(5, 28, "Points: {} ".format(self.score()), ugfx.WHITE) ugfx.text(5, 48, "Turn: {} ".format(self.turn), ugfx.WHITE) + # Blank out the status/resource area + ugfx.area(0, 275, 240, 50, ugfx.BLACK) + + # Status line + ugfx.text(5, 275, self.status, ugfx.WHITE) + # Player's resources - ugfx.area(0, 290, 240, 30, ugfx.BLACK) offset = int(ugfx.width() / len(self.resources)) square = int(offset / 3) for i in range(len(self.resources)): @@ -806,8 +838,7 @@ class Dice: class GameBoard(State): - MAIN_MENU = 0 - ACTION_MENU = 1 + MENU = 0 # List of resources (pre-randomised to combat the not-very random number # generator) that make up the hexes on the game board for 4 players @@ -930,6 +961,9 @@ class GameBoard(State): # The dice roller self.dice = Dice() + # Cheat code counter + self.cheat = 0 + def get_roads_for_settlement(self, settlement): """Return a list of roads that connect to the given settlement""" roads = [] @@ -970,26 +1004,28 @@ class GameBoard(State): Buttons.enable_interrupt(Buttons.BTN_Menu, self._button_callback) Buttons.enable_interrupt(Buttons.BTN_A, self._button_callback) Buttons.enable_interrupt(Buttons.BTN_B, self._button_callback) - Buttons.enable_interrupt(Buttons.BTN_Star, self._button_callback) Buttons.enable_interrupt(Buttons.BTN_Hash, self._button_callback) # For moving the robber and building selections Buttons.enable_interrupt(Buttons.JOY_Up, self._button_callback) Buttons.enable_interrupt(Buttons.JOY_Down, self._button_callback) Buttons.enable_interrupt(Buttons.JOY_Left, self._button_callback) Buttons.enable_interrupt(Buttons.JOY_Right, self._button_callback) + # Cheat code button + Buttons.enable_interrupt(Buttons.BTN_5, self._button_callback) def deinitialise(self): # Unregister callbacks Buttons.disable_interrupt(Buttons.BTN_Menu) Buttons.disable_interrupt(Buttons.BTN_A) Buttons.disable_interrupt(Buttons.BTN_B) - Buttons.disable_interrupt(Buttons.BTN_Star) Buttons.disable_interrupt(Buttons.BTN_Hash) # For moving the robber and building selections Buttons.disable_interrupt(Buttons.JOY_Up) Buttons.disable_interrupt(Buttons.JOY_Down) Buttons.disable_interrupt(Buttons.JOY_Left) Buttons.disable_interrupt(Buttons.JOY_Right) + # Cheat code button + Buttons.disable_interrupt(Buttons.BTN_5) # Ensure all hexes are drawn next time we enter this state for h in self.hexes: @@ -998,10 +1034,7 @@ class GameBoard(State): def _button_callback(self, btn): if not self.interactive_mode: if btn == Buttons.BTN_Menu: - self.selection = GameBoard.MAIN_MENU - self.done = True - if btn == Buttons.BTN_Star: - self.selection = GameBoard.ACTION_MENU + self.selection = GameBoard.MENU self.done = True if btn == Buttons.BTN_Hash: # Only roll the dice if not already rolled @@ -1020,19 +1053,31 @@ class GameBoard(State): # Activate the robber on a seven if num == 7: self.interactive_mode = GameBoard.ROBBER_MODE - # TODO: give user hint about moving the robber + self.player.status = Player.STATUS_MOVE_ROBBER + else: + self.player.status = Player.STATUS_ACTIONS + self.redraw = True + # Cheat code to get more resources for testing + if btn == Buttons.BTN_5 and TEST_MODE: + self.cheat = self.cheat + 1 + if self.cheat == 5: + self.cheat = 0 + for r in self.player.resources: + r.increment(5) self.redraw = True elif self.interactive_mode == GameBoard.ROBBER_MODE: h_current = self.get_robber_hex() if btn == Buttons.BTN_A: + self.redraw = True # The robber may not stay in the same hex, ensure it moved if h_current != self.robber_hex: self.robber_hex = h_current self.robber_hex.set_highlight(False) self.interactive_mode = None - self.redraw = True + self.player.status = Player.STATUS_ACTIONS # TODO: Steal a card from a player at this hex - # TODO: tell user that the robber must move + else: + self.player.status = Player.STATUS_MUST_MOVE_ROBBER if btn == Buttons.JOY_Up: self._move_robber(h_current, 4) if btn == Buttons.JOY_Down: @@ -1058,6 +1103,10 @@ class GameBoard(State): self.player.pay(self.build_cost) self.interactive_mode = None self.redraw = True + if self.dice.total(): + self.player.status = Player.STATUS_ACTIONS + else: + self.player.status = Player.STATUS_ACTIONS_DICE if btn == Buttons.JOY_Left or btn == Buttons.JOY_Up: self._select_prev_build_candidate(self.build_candidates) if btn == Buttons.JOY_Right or btn == Buttons.JOY_Down: @@ -1138,7 +1187,9 @@ class GameBoard(State): self.build_candidates[0].set_selection(True) self.build_cost = cost self.interactive_mode = mode - # TODO: tell user there are no valid candidates + self.player.status = Player.STATUS_BUILD + else: + self.player.status = Player.STATUS_NO_BUILD class Settlers: @@ -1194,9 +1245,7 @@ class Settlers: elif self.state == Settlers.GAME: x = self.game.run() - if x == GameBoard.MAIN_MENU: - self.enter_state(Settlers.MAIN_MENU) - if x == GameBoard.ACTION_MENU: + if x == GameBoard.MENU: self.enter_state(Settlers.ACTION_MENU) elif self.state == Settlers.ACTION_MENU: @@ -1208,6 +1257,8 @@ class Settlers: self.enter_state(Settlers.ACTION_TRADE_MENU) if x == ActionMenu.END_TURN: self.enter_state(Settlers.ACTION_END_TURN) + if x == ActionMenu.EXIT_GAME: + self.enter_state(Settlers.MAIN_MENU) if x == ActionMenu.BACK: self.enter_state(Settlers.GAME)