def grant_hero(game): grantee = random.choice(game.get_actors()) # can only get hero if above certain fame threshold, higher the more heroes you've been granted so far if (grantee.num_heroes_granted() >= len(fame.HERO_GRANT_THRESHOLD) or grantee.get_fame() < fame.HERO_GRANT_THRESHOLD[grantee.num_heroes_granted()]): return None, None hero_sites = [curr_site for curr_site in grantee.get_sites()] if len(hero_sites) == 0: # nowhere for hero to appear return None, None grant_site = random.choice(hero_sites) # generate hero hero_type = unit.random_hero_type() granted_hero = hero.Hero(hero_type) grant_site.add_for_hire(granted_hero) grantee.granted_hero() # signal the granting of a hero event_manager.queue_event( Event(event_manager.HERO_GRANTED, [grantee, grant_site.get_name()])) return "A new hero has offered his services in ", game.get_map().get_zone( grant_site.get_hex().x, grant_site.get_hex().y)
def check_revolt(self, hex_map): if random.random() >= self.revolt_chance(): return False # print self.get_name() + "Revolting!" site_hex = self.get_hex() # revolt happened if site_hex.get_garrison() != None: site_hex.get_garrison().eliminate() active_group = site_hex.get_active_group() if active_group != None: open_neighbors = [ neighbor for neighbor in hex_map.get_neighbors(site_hex.x, site_hex.y) if neighbor.legal_move(active_group) ] if len(open_neighbors) == 0: active_group.eliminate() else: active_group.move(random.choice(open_neighbors), 0) # transfer site to new owner old_owner = self.get_owner() self.transfer(self.default_owner) event_manager.queue_event( Event(event_manager.SITE_REVOLT, [self, old_owner])) return True
def update_stats(self, stat_item, equipping, adding): for mod_stat in [ curr_trait for curr_trait in stat_item.get_traits() if curr_trait in trait.stat_mods ]: stat_mod_value = stat_item.get_traits()[mod_stat] # negative stat adjustments are adjusted on add/remove from inventory, positive # adjustments on add/remove from equipment if (stat_mod_value < 0) == equipping: continue # if item coming off, reverse mod if not adding: stat_mod_value = -stat_mod_value if mod_stat == trait.STRENGTH_MOD: self.strength += stat_mod_value elif mod_stat == trait.ARMOR_MOD: self.armor += stat_mod_value elif mod_stat == trait.SPEED_MOD: self.speed += stat_mod_value elif mod_stat == trait.LOOT_MOD: self.looting += stat_mod_value elif mod_stat == trait.REPUTATION_MOD: rep_adj_type = reputation.ITEM_EQUIP if adding else reputation.ITEM_UNEQUIP reputation.adjust_reputation(rep_adj_type, stat_item, self.owner, delta=stat_mod_value) elif mod_stat == trait.INCOME_MOD: self.owner.adjust_income(stat_mod_value, income.ITEM_INCOME) event_manager.queue_event( Event(event_manager.UNIT_STATS_CHANGED, [self]))
def victory_adjustments(self, win_group, lose_group, win_player, lose_player, loser_eliminated): reputation_adj = 0 item_gained = None if loser_eliminated: # grant reputation to winner if it was an active player that defeated a monster army patrol of # high enough level reputation_adj = reputation.adjust_reputation( reputation.DESTROYED_GROUP, lose_group, win_player) # if a lone hero kills a unit with the QUEST trait, grant him an item of level = level of monster if win_group.num_units() == 1 and isinstance( win_group.get_unit(0), hero.Hero): for unit_index in range(lose_group.num_units()): curr_unit = lose_group.get_unit(unit_index) if curr_unit.has_trait(trait.QUEST): item_gained = item.random_item(curr_unit.get_level()) win_group.add_item(item_gained) if reputation_adj != 0 or item_gained != None: event_manager.queue_event( Event(event_manager.COMBAT_SPOILS, [reputation_adj, item_gained]))
def check_for_event(game): curr_week = game.get_turn().week # # first check to see if a horde is spawned. # event_description, event_zone = generate_horde(game, curr_week) # # if no horde, check for normal random event # if event_description == None: # TODO: scale chance of event with map size to get constant chance/area if random.random() > EVENT_CHANCE: return # determine type of event event_type_roll = random.random() if event_type_roll > RARE_THRESHOLD: event_func = choose_event_func(rare_events, curr_week) elif event_type_roll > UNCOMMON_THRESHOLD: event_func = choose_event_func(uncommon_events, curr_week) else: event_func = choose_event_func(common_events, curr_week) event_description, event_zone = event_func(game) if event_description == None: return event_manager.queue_event( Event(event_manager.RANDOM_EVENT, [event_description + event_zone.get_name()]))
def execute(self, game): if self.from_backpack: self.unit.discard_item(self.unit.get_backpack_item(self.index)) else: self.unit.discard_item(self.unit.get_equipped_item(self.index)) event_manager.queue_event( Event(event_manager.ITEM_REMOVED, [self.unit]))
def ai(self, curr_game): self.move_active_groups(curr_game) assert (len(process_manager.process_list) == 0) # spawn new patrols at end of turn for curr_site in self.sites: # non-actors throw out spawn groups rather than actively taking over the map if (not self.is_actor() and curr_site.is_active( ) #and curr_site not in self.site_linked_groups and curr_site.hex_loc.get_active_group() == None): spawn_hex = curr_game.get_map().get_spawn_hex( curr_site.hex_loc) if spawn_hex != None: curr_site.spawn_group(curr_game) #new_group = curr_site.spawn_group(curr_game) # if new_group != None: # new_patrol.set_reputation_value(curr_site.get_level() * self.patrol_reputation) # new_group.initialize(spawn_hex) # if new_group.site_linked(): # # make sure each site only has one site-linked group at at time # self.site_patrols[curr_site] = new_group event_manager.queue_event( Event(event_manager.COMMAND_ISSUED, [EndTurnCommand(self)]))
def select_hex(self, hex_x, hex_y): if hex_x < 0 or hex_x >= self.map_width or hex_y < 0 or hex_y >= self.map_height: return None self.selected_hex = Loc(hex_x, hex_y) event_manager.queue_event( Event(event_manager.HEX_SELECTED, [self.selected_hex])) return self.selected_hex
def adjust_gold(self, delta_gold): # can't go below 0 if self.gold + delta_gold < 0: delta_gold = -self.gold self.gold += delta_gold event_manager.queue_event( Event(event_manager.PLAYER_STATUS_CHANGE, [self, 'Gold', self.gold]))
def handle_child_drop(self, event, new_index): dropped_icon = event.dropped if dropped_icon.index[0] != new_index[0]: command = misc_commands.ItemTransferCommand(self.unit, dropped_icon.index[0] == PACK_SLOT, dropped_icon.index[1]) event_manager.queue_event(Event(event_manager.COMMAND_ISSUED, [command])) return True return False
def remove_site(self, site): linked_list_remove(self.sites, site) self.sites.remove(site) self.adjust_income(-site.get_income(), income.SITE_INCOME) site.owner = None self.get_mask().seer_removed(site.get_hex(), site.get_sight_range()) event_manager.queue_event( Event(event_manager.SITE_LOST, [self, site.get_name()]))
def check_drop_transfer(self, dropped_icon): if dropped_icon in self.partner_renderer.unit_labels: # unit transfer orig_index = self.partner_renderer.unit_labels.index(dropped_icon) to_garrison = self.garrison command = misc_commands.UnitTransferCommand(self.partner_renderer.curr_group.get_hex(), to_garrison, orig_index) event_manager.queue_event(Event(event_manager.COMMAND_ISSUED, [command])) return True return False
def execute(self, game): self.site.add_upgrade(self.upgrade_name) self.site.get_owner().adjust_gold(-self.cost) garrison = self.site.get_hex().get_garrison() if garrison != None: garrison.update_trait_effects() self.site.adjust_income( game.get_map()) # some upgrades effect income, so adjust it event_manager.queue_event( Event(event_manager.SITE_UPGRADED, [self.site, self.upgrade_name]))
def increment(self): self.day += 1 event_manager.queue_event( Event(event_manager.DAY_START, [self.week, self.day])) if self.day == 8: self.day = 1 self.week += 1 event_manager.queue_event( Event(event_manager.WEEK_START, [self.week]))
def execute(self, game): if self.from_backpack: sold_item = self.unit.get_backpack_item(self.index) else: sold_item = self.unit.get_equipped_item(self.index) self.unit.get_owner().adjust_gold(sold_item.get_gold_value()) self.unit.discard_item(sold_item) event_manager.queue_event( Event(event_manager.ITEM_REMOVED, [self.unit]))
def ranged_attack(firers): firers.ranged = None firers.opponent.ranged = None firers.opponent.index = -1 attacker = firers.curr_unit() target_index = -1 if attacker.has_trait(trait.ASSASSIN): # special targeting rules, look for support unit closest to back of enemy group. # if none found, fall through to normal targeting rules target_index = firers.opponent.num_units() - 1 while (target_index >= 0): candidate = firers.opponent.get_unit(target_index) if candidate.is_alive() and candidate.is_support( ) and attacker.get_ranged_strength(candidate) > 0: break target_index -= 1 if target_index == -1: target_index = max(0, firers.index - 1) # long range units can fire more than one slot ahead range = trait.MAX_RANGE if attacker.has_trait(trait.LONG_RANGE) else 1 while (firers.index - target_index < range and target_index > 0 and (firers.opponent.get_unit(target_index) == None or not firers.opponent.get_unit(target_index).is_alive())): target_index -= 1 target = firers.opponent.get_unit(target_index) if target != None and target.is_alive(): firers.opponent.index = target_index strength = attacker.get_ranged_strength(target) firers.ranged = strength event_manager.queue_event( Event(event_manager.RANGED_ATTACK, [firers.group, firers.index])) if check_20_val(strength): check_block(firers.opponent, target_index, RANGED_COMBAT) # if hit, check for splash if attacker.has_trait(trait.SPLASH): splash_targets = [target_index - 1, target_index + 1] for splash_index in splash_targets: splash_target = firers.opponent.get_unit(splash_index) # if target is viable, and this unit has a positive ranged strength against it, it takes # an attack and must block or be hit if splash_target != None and splash_target.is_alive( ) and attacker.get_ranged_strength(splash_target) > 0: check_block(firers.opponent, splash_index, RANGED_COMBAT) return True return False return False
def event_handler(self, event): if event.type == component.MOUSE_DOWN: event_manager.queue_event( Event(event_manager.BUTTON_CLICK, [self, self.down])) self.toggle() if self.on_toggle != None: self.on_toggle(self.down) if event.type in component.mouse_events: return True return False
def handle_child_drop(self, event, new_index): dropped_icon = event.dropped if dropped_icon in self.unit_labels: # unit shift orig_index = self.unit_labels.index(dropped_icon) command = misc_commands.UnitShiftCommand(self.curr_group, orig_index, new_index) event_manager.queue_event(Event(event_manager.COMMAND_ISSUED, [command])) return True if self.check_drop_transfer(dropped_icon): return True return False
def finish(self): # print ("sending update for phase " + self.curr_phase() + " attacker index " + str(self.attackers.index) + # " defender index " + str(self.defenders.index) + " attacker strength " + str(self.attackers.get_strength(self.curr_phase())) + # " defender strength " + str(self.defenders.get_strength(self.curr_phase()))) event_manager.queue_event( Event(event_manager.COMBAT_UPDATE, [ self.curr_phase(), self.attackers.index, self.defenders.index, self.attackers.get_strength(self.curr_phase()), self.defenders.get_strength(self.curr_phase()) ])) if self.is_dead(): self.release_lock()
def advance_turn(self): event_manager.queue_event( Event(event_manager.TURN_END, [self.get_curr_player(), self.turn.week, self.turn.day])) self.curr_player_index = (self.curr_player_index + 1) % len( self.players) if self.curr_player_index == 0: self.turn.increment() self.hex_map.start_day(self.turn) random_event.check_for_event(self) self.start_turn()
def event_handler(self, event): if event.type == component.MOUSE_DOWN: self.down = True return True elif event.type == component.MOUSE_UP: self.down = False return True elif event.type == component.MOUSE_CLICK: event_manager.queue_event( Event(event_manager.BUTTON_CLICK, [self, self.down])) if self.on_click != None: self.on_click() return True return super(Button, self).event_handler(event)
def handle_battle_end(self, lose_force, loser_eliminated): for force in self.forces: # clear temporary combat traits force.clear_temporary_traits() win_group, lose_group = lose_force.opponent.group, lose_force.group win_player, lose_player = win_group.get_owner(), lose_group.get_owner() self.victory_adjustments(win_group, lose_group, win_player, lose_player, loser_eliminated) retreat_chance = 0 retreated = False if lose_force == self.defenders and not loser_eliminated and self.defense_hex.get_active_group( ) == lose_group: # check for retreat retreat_chance = self.retreat_chance(lose_group, win_group) if random.random() < retreat_chance: # look for valid retreat hex retreat_dir = hexgrid.get_direction(win_group.get_hex(), lose_group.get_hex()) retreat_dirs = [(retreat_dir - 1) % 6, retreat_dir, (retreat_dir + 1) % 6] retreat_locs = [ hexgrid.get_neighbor(lose_group.get_hex(), dir) for dir in retreat_dirs ] retreat_hexes = [ self.hex_map.get_hex(x, y) for x, y in retreat_locs ] retreat_hexes = [ curr_hex for curr_hex in retreat_hexes if (curr_hex != None and curr_hex.legal_move(lose_group) and not curr_hex.is_blocked(lose_group)) ] if len(retreat_hexes) > 0: lose_group.move(random.choice(retreat_hexes), 0) retreated = True event_manager.queue_event( Event(event_manager.COMBAT_RETREAT, [win_group, lose_group, retreat_chance, retreated])) # advance to retreat phase self.phase_index += 1 return loser_eliminated
def remove_unit(self, unit_to_remove, transfer=False): if unit_to_remove.is_alive(): self.live_unit_count -= 1 self.units.remove(unit_to_remove) event_manager.queue_event(Event(event_manager.UNIT_REMOVED, [self])) if not transfer: self.owner.lose_unit(unit_to_remove) self.compute_level() self.update_trait_effects() unit_to_remove.set_group(None) return unit_to_remove
def check_block(force, index, phase=MELEE_COMBAT): attacker = force.opponent.curr_unit() target = force.get_unit(index) if target == None or not target.is_alive(): # not gonna be blocking! return None prev_unit = force.get_unit(index - 1) stalwart_defense = prev_unit.get_armor( ) if prev_unit and prev_unit.has_trait(trait.GUARDIAN) else 0 armor = target.get_armor() if target.has_trait( trait.HEAVY_ARMOR ) and phase == RANGED_COMBAT and not attacker.has_trait(trait.SPLASH): armor *= 2 armor = max(armor, stalwart_defense) armor -= attacker.trait_value(trait.PIERCE) # restrain target, if applicable if attacker.has_trait(trait.RESTRAIN): target.set_trait(trait.RESTRAINED, attacker.trait_value(trait.RESTRAIN)) if check_20_val(armor) or (attacker.is_army() and target.has_trait(trait.ELUSIVE)): event_manager.queue_event( Event(event_manager.UNIT_BLOCK, [force.group, index])) return True else: num_wounds = 1 + attacker.trait_value(trait.DEADLY_BLOW) target.wound(num_wounds) if attacker.has_trait(trait.VAMPIRIC) and attacker.is_wounded(): attacker.heal() if check_10_val(attacker.trait_value( trait.BURN)) and target.is_alive(): target.set_trait(trait.BURNING, True) if not target.is_alive(): force.opponent.add_kill(force) event_manager.queue_event( Event(event_manager.UNIT_HIT, [force.group, index])) return False
def consume_trait(self, trait): ret_val = False if super(Hero, self).consume_trait(trait): ret_val = True else: for curr_item in self.equipped_items: if curr_item != None and curr_item.consume_trait(trait): ret_val = True break if ret_val == True: self.curr_traits[trait] = self.curr_traits[trait] - 1 event_manager.queue_event( Event(event_manager.UNIT_STATS_CHANGED, [self])) return ret_val
def add_unit(self, new_unit, index=None, transfer=False): if not self.do_add(new_unit, index): return event_manager.queue_event(Event(event_manager.UNIT_ADDED, [self])) if new_unit.is_alive(): self.live_unit_count += 1 if not transfer: self.owner.gain_unit(new_unit) self.compute_level() if self.curr_hex != None: self.update_trait_effects() return True
def get_lock(self): global combat_locked_by # TODO: could lock only human visibile combats if events from non-human visible proceses were suppressed. # performance boost. if combat_locked_by == self: return True if combat_locked_by == None: combat_locked_by = self event_manager.queue_event( Event(event_manager.COMBAT_START, [ self.attackers.group, self.defenders.group, self.defense_hex ])) return True return False
def event_handler(self, event): if event.type == component.TICK: event_manager.queue_event(Event(event_manager.TICK, [])) return True # redirect arrow events to map: if event.type == component.KEY_UP or event.type == component.KEY_DOWN: if (event.key == component.K_DOWN or event.key == component.K_UP or event.key == component.K_LEFT or event.key == component.K_RIGHT): return self.map_renderer.event_handler(event) if event.type == component.KEY_DOWN: # if (event.key == pygame.K_z): # self.view.zoom_out() # elif (event.key == pygame.K_a): # self.view.zoom_in() if (event.key == pygame.K_m): self.minimap() elif (event.key == pygame.K_b): self.toggle_zone_borders() elif (event.key == pygame.K_n): self.next_group() elif (event.key == pygame.K_p): self.previous_group() elif (event.key == pygame.K_a): self.previous_site() elif (event.key == pygame.K_s): self.next_site() elif (event.key == pygame.K_g): if self.debug_mask_on: self.active_mask = self.curr_game.get_mask() self.debug_mask_on = False else: self.debug_mask_on = True self.active_mask = self.curr_game.get_debug_mask() self.update_window_data() elif (event.key == pygame.K_e and self.activity_allowed): return self.end_turn() elif (event.key == pygame.K_c and self.activity_allowed): self.center_view() elif event.type == pygame.QUIT: self.quit_to_desktop = True event_manager.queue_event( Event(event_manager.QUIT, [self.save_on_quit]))
def heal_or_revive(healers, heal_trait, success_func, target_func): #target nearest valid unit, preferring unit toward front forward = healers.index - 1 backward = healers.index + 1 target_indices = [] max_targets = 1 while len(target_indices) < max_targets and ( forward >= 0 or backward < healers.num_units()): if forward >= 0 and target_func(healers.get_unit(forward)): target_indices.append(forward) if len(target_indices) < max_targets and backward < healers.num_units( ) and target_func(healers.get_unit(backward)): target_indices.append(backward) backward += 1 forward -= 1 if len(target_indices) == 0: # no valid target return False death_aura = healers.group.get_highest_trait(trait.DEATH_AURA) death_aura = max( death_aura, healers.opponent.group.get_highest_trait(trait.DEATH_AURA)) life_aura = healers.group.get_highest_trait(trait.LIFE_AURA) life_aura = max(life_aura, healers.opponent.group.get_highest_trait(trait.LIFE_AURA)) heal_mod = life_aura - death_aura strength = healers.curr_unit().trait_value(heal_trait) + heal_mod event_manager.queue_event( Event(event_manager.HEAL_ATTEMPT, [healers.group, healers.index])) ret_val = False for index in target_indices: target = healers.get_unit(index) if check_10_val(strength): success_func(target) event_manager.queue_event( Event(event_manager.UNIT_HEAL, [healers.group, index])) ret_val = True return ret_val
def event_handler(self, event): if event.type == component.KEY_DOWN: key_val = event.unicode # equip/unequip/destroy selected item if key_val == 't' and self.selected_item != None: # equip/unequip selected item command = misc_commands.ItemTransferCommand(self.unit, self.selected_item[0] == PACK_SLOT, self.selected_item[1]) event_manager.queue_event(Event(event_manager.COMMAND_ISSUED, [command])) return True if key_val == 'x' and self.selected_item != None: # throw away selected item command = misc_commands.ItemDiscardCommand(self.unit, self.selected_item[0] == PACK_SLOT, self.selected_item[1]) event_manager.queue_event(Event(event_manager.COMMAND_ISSUED, [command])) return True if key_val == 's' and self.selected_item != None: # sell selected item self.sell_selected() return True return super(ItemDialog, self).event_handler(event)