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
master
Mat Booth 2018-11-24 12:04:57 +00:00
parent df0a13c1ab
commit 82c0cb378c
1 changed files with 69 additions and 18 deletions

View File

@ -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)