Skip to content
Browse files

Fixing clickable bug fixes and some slight polish

- two armies after attack no longer prompts user
- no longer able to select enemy territory in fortify
- origin fortify territory forced highlight
- clickables now wait for mouse release confirmation
- clickables now triggered by mouse click
- now allowing cancel action in attack and fortify DFA
  • Loading branch information...
1 parent 4aef651 commit a4bcc76e78535f4d09cc05b27486027c58ebfbff @elElmo elElmo committed Apr 1, 2013
View
BIN resources/risk_board.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
11 risk/graphics/assets/clickable.py
@@ -4,8 +4,10 @@
from pygame.font import Font
import risk.graphics.assets
+import risk.graphics.event
from risk.graphics.assets import base
from risk.graphics.assets.base import PicassoAsset
+from risk.graphics.event import wait_for_mouse_release
_FONT = 'resources/Vera.ttf'
class ClickableAsset(PicassoAsset):
@@ -38,8 +40,8 @@ def __init__(self, x, y, width, height, msg, size=16,
PicassoAsset.__init__(self, self.normal, x, y)
def draw(self):
- if not self.disabled and (self.mouse_hovering() or \
- self.force_highlight):
+ if self.force_highlight or (self.mouse_hovering() and \
+ not self.disabled):
return self._highlighted_surface()
else:
return self._normal_surface()
@@ -55,6 +57,11 @@ def mouse_hovering(self, mouse_pos=None):
self.y + self.offset_y).collidepoint(
mouse_pos) and not self.disabled
+ # take control of main thread until mouse released
+ def confirmed_click(self):
+ release = wait_for_mouse_release()
+ return self.mouse_hovering(release.pos)
+
def _normal_surface(self):
return self.normal
View
18 risk/graphics/assets/dialog.py
@@ -5,7 +5,7 @@
import risk.graphics.assets
from risk.graphics.picasso import get_picasso
-from risk.graphics.event import wait_for_event
+from risk.graphics.event import wait_for_event, wait_for_mouse_click
from risk.graphics.event import pump
from risk.graphics.assets.base import BLACK, BROWN, WHITE
from risk.graphics.assets.base import PicassoAsset
@@ -168,15 +168,13 @@ def draw(self):
def get_result(self, poll_sleep):
done = False
while not done:
- event = wait_for_event()
- if event.type == pygame.MOUSEBUTTONDOWN:
- if self.slider.mouse_hovering(event.pos):
- self.drag_slider(poll_sleep)
- elif self.being_dragged(event.pos):
- self.drag_dialog()
- elif event.type == pygame.MOUSEBUTTONUP and \
- self.finished_button.mouse_hovering(event.pos):
- done = True
+ event = wait_for_mouse_click()
+ if self.slider.mouse_hovering(event.pos):
+ self.drag_slider(poll_sleep)
+ elif self.being_dragged(event.pos):
+ self.drag_dialog()
+ elif self.finished_button.mouse_hovering(event.pos):
+ done = self.finished_button.confirmed_click()
return self.current
def reset(self):
View
18 risk/graphics/event.py
@@ -18,6 +18,9 @@
_NO_BLOCK = False
mutex = threading.Semaphore()
+###############################################################################
+## Critical section functions
+#
def wait_for_event():
# this is a bit strange, but pygame will invoke pump internally so there's
# really no reason to call pump when waiting for event
@@ -46,3 +49,18 @@ def pump():
pygame.event.pump()
mutex.release()
+###############################################################################
+## Safe functions that don't touch CS
+#
+def wait_for_event_type(event_type):
+ event = wait_for_event()
+ while event.type != event_type:
+ event = wait_for_event()
+ return event
+
+def wait_for_mouse_release():
+ return wait_for_event_type(pygame.MOUSEBUTTONUP)
+
+def wait_for_mouse_click():
+ return wait_for_event_type(pygame.MOUSEBUTTONDOWN)
+
View
3 risk/graphics/graphics.py
@@ -196,5 +196,6 @@ def pressed_clickables(mouse_pos, storage='buttons'):
clicked = []
for name, button in storage.iteritems():
if button.mouse_hovering(mouse_pos):
- clicked.append((name, button))
+ if button.confirmed_click():
+ clicked.append((name, button))
return clicked
View
99 risk/graphics/input.py
@@ -17,6 +17,7 @@
from risk.errors.battle import RiskBattleError
from risk.graphics.event import wait_for_event, get_events
+from risk.graphics.event import wait_for_mouse_click
from risk.graphics.datastore import Datastore
from risk.graphics.picasso import get_picasso
from risk.graphics.assets.player import *
@@ -53,18 +54,18 @@ def get_clicked_buttons(mouse_pos):
def handle_user_mouse_input(game_master, state_entry):
player = game_master.current_player()
state_entry(player, game_master)
- #scan_pygame_mouse_event(player, game_master, state_entry)
+ #wait_for_mouse_click(player, game_master, state_entry)
def get_all_clickables():
datastore = Datastore()
return datastore.get_storage('buttons').values() + \
datastore.get_storage('territories').values()
-def disable_clickables():
+def disable_all_clickables():
for clickable in get_all_clickables():
clickable.disabled = True
-def enable_clickables():
+def enable_all_clickables():
for clickable in get_all_clickables():
clickable.disabled = False
@@ -81,21 +82,24 @@ def enable_adjacent_territories(origin):
for neighbour in origin.neighbours.values():
assets[neighbour.name].disabled = False
-def scan_pygame_mouse_event():
- _WAITING_FOR_INPUT = True
-
- while _WAITING_FOR_INPUT:
- event = wait_for_event()
- if event.type == pygame.MOUSEBUTTONUP:
- return event
+#def wait_for_mouse_click():
+# _WAITING_FOR_INPUT = True
+#
+# while _WAITING_FOR_INPUT:
+# event = wait_for_event()
+# if event.type == pygame.MOUSEBUTTONDOWN:
+# return event
-def wait_for_territory_click():
+def wait_for_territory_click(allow_fail=False):
_NO_TERRITORY_CLICKED = True
while _NO_TERRITORY_CLICKED:
- event = scan_pygame_mouse_event()
+ event = wait_for_mouse_click()
for name, clickable in get_clicked_territories(event.pos):
if isinstance(clickable, TerritoryAsset):
return clickable
+ # short circuit condition
+ if allow_fail:
+ return None
###############################################################################
## Reinforce phase DFA
@@ -110,7 +114,7 @@ def reinforce_phase(player, game_master):
# core state machine
disable_enemy_territories(player)
while player.reserves > 0:
- event = scan_pygame_mouse_event()
+ event = wait_for_mouse_click()
for name, clickable in graphics.pressed_clickables(event.pos,
'territories'):
if isinstance(clickable, TerritoryAsset):
@@ -121,7 +125,7 @@ def reinforce_phase(player, game_master):
except GameMasterError:
reinforce_add_army_fail(player, game_master, territory)
# exit state
- enable_clickables()
+ enable_all_clickables()
picasso.remove_asset(LAYER, reserve_count_asset)
def reinforce_add_army(player, game_master, territory, number_of_armies=1):
@@ -142,7 +146,7 @@ def attack_phase(player, game_master):
done = False
while not done:
disable_enemy_territories(player)
- event = scan_pygame_mouse_event()
+ event = wait_for_mouse_click()
for name, clickable in get_clicked_territories(event.pos):
if isinstance(clickable, TerritoryAsset):
if clickable.territory.owner == player:
@@ -151,38 +155,51 @@ def attack_phase(player, game_master):
for name, clickable in get_clicked_buttons(event.pos):
if name == 'next':
done = True
- enable_clickables()
+ enable_all_clickables()
def attack_choose_target(player, game_master, origin_asset):
origin = origin_asset.territory
picasso = get_picasso()
datastore = Datastore()
feedback_asset = datastore.get_entry('attack_feedback')
picasso.add_asset(LAYER, feedback_asset)
- disable_clickables()
+ disable_all_clickables()
origin_asset.force_highlight = True
enable_adjacent_territories(origin)
- target = wait_for_territory_click().territory
+ target_asset = wait_for_territory_click(allow_fail=True)
+ target = None
+ if target_asset:
+ target = target_asset.territory
+ if not target:
+ pass
+ else:
+ attack_perform_attack(player, game_master, origin, target)
+ picasso.remove_asset(LAYER, feedback_asset)
+ origin_asset.force_highlight = False
+ enable_all_clickables()
+
+def attack_perform_attack(player, game_master, origin, target):
try:
success = game_master.player_attack(player, origin.name, target.name)
if success:
- attack_success_move_armies(player, game_master, origin, target)
+ if origin.armies > 2:
+ attack_success_move_armies(player, game_master, origin, target)
+ else:
+ game_master.player_move_armies(player, origin.name,
+ target.name, 1)
else:
attack_failed(player, game_master, origin, target)
except (GameMasterError, RiskBattleError, KeyError):
pass
- finally:
- picasso.remove_asset(LAYER, feedback_asset)
- origin_asset.force_highlight = False
- enable_clickables()
+
def attack_success_move_armies(player, game_master, origin, target):
picasso = get_picasso()
dialog = BlockingSliderDialogAsset(DIALOG_X, DIALOG_Y, 'Attack Move', 1,
origin.armies, slider_update, [origin, target])
dialog.add_text(16, 16, "Attack was successful!")
dialog.add_text(16, 32, "How many armies to move?")
- disable_clickables()
+ disable_all_clickables()
picasso.add_asset(LAYER, dialog)
done = False
while not done:
@@ -197,7 +214,7 @@ def attack_success_move_armies(player, game_master, origin, target):
except ValueError:
# we really shouldn't get a parsing error from numeric dialog
raise
- enable_clickables()
+ enable_all_clickables()
picasso.remove_asset(LAYER, dialog)
def attack_failed(player, game_master, origin, target):
@@ -208,47 +225,61 @@ def attack_failed(player, game_master, origin, target):
#
def fortify_phase(player, game_master):
+ disable_enemy_territories(player)
done = False
# TODO merge with attack phase block
while not done:
- event = scan_pygame_mouse_event()
+ event = wait_for_mouse_click()
for name, clickable in get_clicked_territories(event.pos):
if isinstance(clickable, TerritoryAsset):
if clickable.territory.owner == player:
- fortify_choose_target(player, game_master,
- clickable.territory)
+ fortify_choose_target(player, game_master, clickable)
for name, clickable in get_clicked_buttons(event.pos):
if name == 'next':
done = True
+ enable_all_clickables()
-def fortify_choose_target(player, game_master, origin):
- target = wait_for_territory_click().territory
- if target.owner == player and origin.is_connected(target):
+def fortify_choose_target(player, game_master, origin_asset):
+ origin_asset.disabled = True
+ origin_asset.force_highlight = True
+ origin = origin_asset.territory
+ target_asset = wait_for_territory_click(allow_fail=True)
+ target = None
+ if target_asset:
+ target = target_asset.territory
+ if not target:
+ # cancel
+ pass
+ elif target.owner == player and origin.is_connected(target):
fortify_choose_armies_to_move(player, game_master, origin, target)
else:
- fortify_failed(player, origin, target, NotConnected(None, None))
+ fortify_failed(player, origin, target,
+ TerritoryNotOwnedByPlyer(player))
+ origin_asset.force_highlight = False
+ origin_asset.disabled = False
def fortify_choose_armies_to_move(player, game_master, origin, target):
picasso = get_picasso()
dialog = BlockingSliderDialogAsset(DIALOG_X, DIALOG_Y, 'Fortify', 0,
origin.armies, slider_update, [origin, target])
dialog.add_text(16, 16, "Fortifying...")
dialog.add_text(16, 35, "Select amount of armies to move")
- disable_clickables()
+ disable_all_clickables()
picasso.add_asset(LAYER, dialog)
try:
number_to_move = dialog.get_result(INPUT_POLL_SLEEP)
game_master.player_move_armies(player, origin.name,
target.name, number_to_move)
except GameMasterError as e:
fortify_failed(player, origin, target, e)
- enable_clickables()
+ enable_all_clickables()
picasso.remove_asset(LAYER, dialog)
def fortify_failed(player, origin, target, reason):
picasso = get_picasso()
expected = {
NotConnected: 'The selected territories are not connected!',
+ TerritoryNotOwnedByPlayer: "You do not own %s!" % target.name,
}
msg = expected[reason.__class__] if reason.__class__ in expected.keys() \
else "Unkonwn reason for failure..."

0 comments on commit a4bcc76

Please sign in to comment.
Something went wrong with that request. Please try again.