예제 #1
0
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)
예제 #2
0
    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
예제 #3
0
    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]))
예제 #4
0
    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]))
예제 #5
0
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()]))
예제 #6
0
 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]))
예제 #7
0
    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)]))
예제 #8
0
    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
예제 #9
0
 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]))
예제 #10
0
 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 
예제 #11
0
 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()]))
예제 #12
0
 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
예제 #13
0
 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]))
예제 #14
0
    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]))
예제 #15
0
    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]))
예제 #16
0
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
예제 #17
0
    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
예제 #18
0
 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 
예제 #19
0
 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()
예제 #20
0
    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()
예제 #21
0
 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)
예제 #22
0
    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
예제 #23
0
    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
예제 #24
0
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
예제 #25
0
    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
예제 #26
0
    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
예제 #27
0
    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
예제 #28
0
    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]))
예제 #29
0
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
예제 #30
0
 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)