def deduct_resources(self, team, resource_deduction): self.resources[team] = max(self.resources[team] - resource_deduction, 0) publish_game_event(EventType.E_RESOURCES_LOST, { 'team': team, 'resources_lost': resource_deduction })
def fill_team(self, team, nickname): if team in self.open_teams: self.open_teams.remove(team) self.filled_teams[team] = nickname if len(self.open_teams) == 0: publish_game_event(EventType.E_ALL_TEAMS_FILLED, {})
def handle_phase_build(self, event): # Execute build orders if isinstance(self.current_order, BuildOrder): if self.is_contested(): # Can't build if there's an enemy piece here self.abort_order() else: if self.current_order.new_piece_type in ALL_UNITS: self.play_sound(SoundType.UNIT_CREATED) else: self.play_sound(SoundType.BUILDING_BUILT) publish_game_event( EventType.E_PIECE_BUILT, { 'tx': self.current_order.tx, 'ty': self.current_order.ty, 'team': self.team, 'new_piece_type': self.current_order.new_piece_type }) # Deduct unit price self.get_manager(Manager.TEAM).deduct_resources( self.team, self.get_manager(Manager.TEAM).attr( self.team, self.current_order.new_piece_type, Attribute.PRICE)) # Pop orders once they're executed self.current_order = None
def add_resources(self, team, new_resources): self.resources[team] = clamp(self.resources[team] + new_resources, 0, MAX_RESOURCES) publish_game_event(EventType.E_RESOURCES_GAINED, { 'team': team, 'new_resources': new_resources })
def handle_phase_ranged(self, event): # Execute ranged attack orders if isinstance(self.current_order, RangedAttackOrder): if self.is_contested(): # Can't conduct a ranged attack if there's an enemy on our tile publish_game_event(EventType.E_ORDER_CANCELED, { 'gx': self.gx, 'gy': self.gy, 'team': self.team }) # Abort the order self.current_order = None else: self.play_sound(SoundType.RANGED_ATTACK) publish_game_event( EventType.E_UNIT_RANGED_ATTACK, { 'gx': self.gx, 'gy': self.gy, 'team': self.team, 'tx': self.current_order.tx, 'ty': self.current_order.ty }) # Pop orders once they're executed self.current_order = None
def remove_team(self, team, notify=True): self.open_teams.append(team) del self.filled_teams[team] publish_game_event(EventType.E_TEAM_LEFT, {'team': team}) if notify: self.send_message(MessageCode.TEAM_EMPTIED, team, "")
def cancel(self): super().cancel() publish_game_event(EventType.E_CLOSE_MENU, { 'gx': self.tx, 'gy': self.ty, 'option': None, 'team': self.team })
def set_turn_submitted(self, team): self.turn_submitted[team] = True if self.check_if_ready_to_submit_turns(): self.play_sound(SoundType.ALL_TURNS_SUBMITTED) publish_game_event(EventType.E_ALL_TURNS_SUBMITTED, {}) for team in self.teams: self.turn_submitted[team] = False
def disconnect_from_host(self, notify_host=True): if notify_host: self.send_message(MessageCode.DROP_CONNECTION, self.team, self.nickname) self.connection.close() self.networked_game = False publish_game_event(EventType.NETWORK_DISCONNECTED_FROM_HOST, {'team': self.team})
def abort_order(self): self.play_sound(SoundType.ORDER_CANCELED) publish_game_event(EventType.E_ORDER_CANCELED, { 'gx': self.gx, 'gy': self.gy, 'team': self.team }) # Abort the order self.current_order = None
def heal_hp(self, heal): max_hp = self.attr(Attribute.MAX_HP) if self.hp < max_hp: self.hp = min(self.hp + heal, max_hp) publish_game_event(EventType.E_PIECE_HEALED, { 'gx': self.gx, 'gy': self.gy, 'team': self.team, 'health': heal })
def quit_network_game(self, notify_host=True): print("Exiting network game") if self.is_host: # Close down the game, notify clients self.send_message(MessageCode.END_CONNECTION, self.team, "") else: # Disconnect from the host self.disconnect_from_host(notify_host) self.networked_game = False publish_game_event(EventType.E_NETWORKING_ERROR, {})
def do_all_planning(self, event=None): try: self.do_preplanning() self.act_on_planning() except Exception as exception: from sys import exc_info # Something's gone wrong, so re-raise this exception with an event in the main thread publish_game_event(EventType.AI_EXCEPTION, { 'exception': exception, 'exc_info': exc_info(), })
def confirm(self): super().confirm() selected_option = self.options[self.menu_pos] publish_game_event( EventType.E_CLOSE_MENU, { 'gx': self.tx, 'gy': self.ty, 'option': selected_option, 'team': self.team })
def remove_piece(self, piece=None): if not piece: piece = self.get_manager(Manager.PIECE).get_piece_at( self.gx, self.gy, self.team) if piece: publish_game_event(EventType.E_PIECE_DEAD, { 'gx': self.gx, 'gy': self.gy, 'team': self.team, 'piece': piece })
def select(self, event): if event.gx == self.gx and event.gy == self.gy and event.team == self.team: available_actions = self.get_available_actions() if not event.selecting_movement and len(available_actions) > 0: publish_game_event( EventType.E_OPEN_MENU, { 'gx': self.gx, 'gy': self.gy, 'team': self.team, 'options': available_actions })
def confirm(self, event): if (event.gx, event.gy) in self.coordinate_set and \ event.team == self.team and event.selecting_movement: publish_game_event( EventType.E_SELECT_TILE, { 'gx': self.gx, 'gy': self.gy, 'option': self.option, 'team': self.team, 'dx': event.gx, 'dy': event.gy, })
def handle_menu_selection(self, event): if event.option == Option.MENU_SAVE_MAP: SESSION.save_map_to_file() elif event.option == Option.MENU_QUIT_BATTLE: publish_game_event(EventType.E_QUIT_BATTLE, {}) elif event.option == Option.MENU_FILL_WITH_CURRENT_TILE: self.fill_with_current_tile() elif event.option == Option.MENU_DESTROY_ALL_PIECES: self.clear_all_pieces() elif event.option == Option.MENU_MIRROR_X: self.mirror_map(mirror_x=True, mirror_y=False) elif event.option == Option.MENU_MIRROR_Y: self.mirror_map(mirror_x=False, mirror_y=True)
def progress_phase(self, event=None): if not self.validate_phase(): return # Publish an event for the end of the orders phase, if necessary if self.phase == BattlePhase.ORDERS: publish_game_event(EventType.END_PHASE_ORDERS, {}) # Clean up at the end of turns if self.phase == BattlePhase.EXECUTE_SPECIAL: publish_game_event(EventType.E_CLEANUP, {}) # Progress the phase new_phase = self.phase.value + 1 if new_phase >= len(BattlePhase): new_phase = 0 self.phase = BattlePhase(new_phase) # Log the start of a new round, if necessary if self.phase == BattlePhase.START_TURN: self.turn += 1 # Publish events for the new phase publish_game_event(EventType.E_NEXT_PHASE, {'new_phase': self.phase}) publish_game_event(self.phase_events[self.phase], {"turn_number": self.turn})
def handle_end_phase_move(self, event): # Apply buffs to allies on adjacent tiles, if necessary armor_share = self.attr(Attribute.ARMOR_SHARE) if armor_share > 0: adjacent_allies = self.get_manager( Manager.PIECE).get_adjacent_pieces(self.gx, self.gy, self.team) for ally in adjacent_allies: ally.temporary_armor += armor_share publish_game_event(EventType.E_ARMOR_GRANTED, { 'gx': ally.gx, 'gy': ally.gy, 'team': ally.team })
def connect_to_host(self): self.send_message(MessageCode.NEW_CONNECTION, Team.NONE, str(self.nickname)) # Block until we receive the map information back from the host. while not self.map_data: try: self.network_step(blocking=True) except Exception as err: print("Failed to connect to host. Aborting.") ERROR_LOGGER.exception("Failed to connect to host", err) SESSION.reset() publish_game_event(EventType.E_QUIT_BATTLE, {}) break
def handle_phase_move(self, event): # Execute move orders if isinstance(self.current_order, MoveOrder): # Note: we don't change our own gx and gy-- the piece manager will do that when it changes our 'address' publish_game_event( EventType.E_UNIT_MOVED, { 'gx': self.gx, 'gy': self.gy, 'team': self.team, 'dx': self.current_order.dx, 'dy': self.current_order.dy }) # Pop orders once they're executed self.current_order = None
def confirm(self): super().confirm() if self.can_confirm_or_cancel(): if not self.get_manager(Manager.TEAM).is_turn_submitted(self.team): if not self.get_manager(Manager.PIECE).get_piece_at(int(self.gx), int(self.gy), self.team) and \ not self.move_ui: self.open_pause_menu() else: publish_game_event( EventType.E_SELECT, { 'gx': int(self.gx), 'gy': int(self.gy), 'team': self.team, 'selecting_movement': self.move_ui is not None })
def handle_text_input(self, event): self.text_input.destroy() self.text_input = None if event.input: if event.tag == Option.NEW_MAP: publish_game_event(EventType.MENU_SELECT_OPTION, { 'option': event.tag, 'mapname': event.input + ".map" }) elif event.tag == Option.JOIN_GAME: publish_game_event(EventType.MENU_SELECT_OPTION, { 'option': event.tag, 'address': event.input }) elif event.tag == Setting.NICKNAME: SETTINGS.set_nonnumeric_setting(Setting.NICKNAME, event.input)
def try_submitting_turn(self, team): if not self.is_turn_submitted(team) and self.get_manager( Manager.PIECE).validate_orders(team): self.turn_submitted[team] = True self.play_sound(SoundType.TURN_SUBMITTED) publish_game_event( EventType.E_TURN_SUBMITTED, { 'team': team, 'orders': self.get_manager(Manager.PIECE).serialize_orders(team) }) if self.check_if_ready_to_submit_turns(): publish_game_event(EventType.E_ALL_TURNS_SUBMITTED, {}) for team in self.teams: self.turn_submitted[team] = False
def remove_team(self, team): del self.resources[team] del self.owned_upgrades[team] del self.piece_attributes[team] self.phase_bars[team].destroy() del self.phase_bars[team] del self.turn_submitted[team] self.teams.remove(team) self.get_manager(Manager.PIECE).destroy_all_pieces_for_team(team) self.get_manager(Manager.PLAYER).handle_team_defeated(team) publish_game_event(EventType.E_TEAM_DEFEATED, {'team': team}) self.check_for_remaining_teams()
def swap_team(self, team): if team in self.ai_teams: ai = self.ais.pop(team) ai.destroy() self.cursors[team] = self.create_cursor(team) self.ai_teams.remove(team) self.human_teams.append(team) elif team in self.human_teams: self.ais[team] = AIPlayer(team) cursor = self.cursors.pop(team) cursor.destroy() self.ai_teams.append(team) self.human_teams.remove(team) # Prompt the new AI to plan its turn publish_game_event(EventType.AI_REPLAN_TURN, {})
def place_piece(self, piece_type): piece = self.get_manager(Manager.PIECE).get_piece_at( self.gx, self.gy, self.team) if piece: # Delete existing pieces first self.remove_piece(piece) if piece_type in ALL_UNITS: self.play_sound(SoundType.UNIT_CREATED) else: self.play_sound(SoundType.BUILDING_BUILT) publish_game_event( EventType.E_PIECE_BUILT, { 'tx': self.gx, 'ty': self.gy, 'team': self.team, 'new_piece_type': piece_type, })
def check_for_remaining_teams(self, event=None): if len(self.teams) <= 1: winning_team = self.get_teams()[0] results = { 'winning_team': winning_team, 'all_teams': self.get_all_teams(), 'team_stats': self.get_manager(Manager.STAT).get_results(), 'winning_pieces': self.get_manager( Manager.PIECE).get_all_pieces_for_team(winning_team), 'turn': self.get_manager(Manager.TURN).turn, } publish_game_event(EventType.E_BATTLE_OVER, {'results': results})
def damage_hp(self, damage, source=None): self.hp -= damage # Add any additional effects or debuffs from the source if source and isinstance(source, Piece): self.last_attacker = source aoe_on_death_gained = source.attr(Attribute.AOE_ON_KILL) if aoe_on_death_gained > 0: self.temporary_aoe_on_death = aoe_on_death_gained money_lost_on_death_gained = source.attr(Attribute.STEAL) if money_lost_on_death_gained > 0: self.temporary_money_lost_on_death = money_lost_on_death_gained publish_game_event(EventType.E_PIECE_DAMAGED, { 'piece': self, 'damage': damage, 'source': source, })