示例#1
0
 def do_attack(attacker, defender, defending_team, surprise=''):
     if attacker in team_1:
         Narrator().cut()
     attacker.busy = True
     attacker.reveal()
     defender.busy = True
     defender.reveal()
     if attacker.hit(defender,
                     1 + initiative[attacker] - initiative[defender]):
         Narrator().add([
             attacker.name, verbs_1 + 'kills', defender.name, surprise,
             at_area, weapon_name[attacker]
         ])
         drops.extend(player_2.drops)
         defending_team.remove(defender)
     else:
         verb = 'attacks' if fight_round == 1 and attacker in team_1 else 'fights'
         Narrator().add([
             attacker.name, verbs_1 + verb, defender.name, at_area,
             weapon_name[attacker]
         ])
         Narrator().apply_stock()
     if defender.is_alive and random(
     ) > defender.courage and defender.can_flee():
         w = defender.weapon
         defender.flee(panic=True)
         if defender.weapon != w:
             drops.append(w)
         defending_team.remove(defender)
示例#2
0
 def loot_weapon(self, weapon: Optional[Weapon] = None, retry=True):
     if weapon is None:
         weapon = Map().pick_weapon(self.current_area)
     if weapon is None or (weapon.damage_mult <= self.weapon.damage_mult and
                           (not weapon.small or Context().time == STARTER
                            or self.bag is None)):
         if retry:
             return self.loot(take_a_break=False)
         else:
             Narrator().add([
                 self.name, 'tries to find a weapon', self.current_area.at,
                 'but can\'t find anything good'
             ])
         return
     if weapon.name == self.weapon.name:
         self.weapon.long_name.replace('\'s', '\'s old')
         Narrator().add([
             self.name, 'picks up', f'a better {weapon.name}',
             self.current_area.at
         ])
     else:
         Narrator().add([
             self.name, 'picks up', weapon.long_name, self.current_area.at
         ])
     self.get_weapon(weapon)
示例#3
0
    def loot(self, take_a_break=True):
        items: List[Item] = []
        for _ in self.acting_players:
            b = Map().pick_item(self)
            if b is not None:
                items.append(b)

        items.sort(key=lambda x: random())
        self.acting_players.sort(key=lambda x: random())

        empty_handed: List[Player] = []
        for player in self.acting_players:
            if len(items):
                item = items.pop(0)
                Narrator().add([
                    player.name, 'picks up', item.long_name,
                    self.current_area.at
                ])
                player.get_item(item)
            else:
                empty_handed.append(player)

        if len(empty_handed):
            verb = 'try' if len(empty_handed) > 1 else 'tries'
            Narrator().add([
                player_names(empty_handed), verb, 'to find loot',
                self.current_area.at, 'but can\'t find anything good'
            ])
示例#4
0
 def check_bag(self):
     if 'unchecked bag' in self.status:
         self.status.remove('unchecked bag')
         bags = [e for e in self._equipment if isinstance(e, Bag)]
         if not len(bags):
             return
         stuff = [e.name for bag in bags for e in bag.content]
         if len(stuff):
             Narrator().new([
                 self.name, 'checks', self.his,
                 'bags,' if len(bags) > 1 else 'bag,', 'finds',
                 format_list(stuff)
             ])
             Narrator().cut()
         else:
             Narrator().new([
                 self.name, 'checks', self.his,
                 'bags,' if len(bags) > 1 else 'bag,', 'finds',
                 'they are' if len(bags) > 1 else 'it is', 'empty'
             ])
             Narrator().cut()
         for i in range(1, len(bags)):
             extra_bag = bags[i]
             self._equipment.remove(extra_bag)
             bags[0].content.extend(extra_bag.content)
         bag_weapons = [
             i for i in bags[0].content if isinstance(i, Weapon)
             and i.damage_mult > self.weapon.damage_mult
         ]
         bag_weapons.sort(key=lambda x: -x.damage_mult)
         if len(bag_weapons):
             bags[0].content.remove(bag_weapons[0])
             self.get_weapon(bag_weapons[0])
示例#5
0
 def fill_bottles(self):
     self.water_upkeep()
     if Map().has_water(self):
         total_water = self.water + sum(b.fill for b in self.bottles)
         self._water = max(1.5, self.water)
         for b in self.bottles:
             b.fill = 1
         new_total_water = self.water + sum(b.fill for b in self.bottles)
         if new_total_water > total_water + 1:
             if len(self.bottles):
                 Narrator().add([
                     self.name, 'fills', self.his,
                     'bottles' if len(self.bottles) > 1 else 'bottle',
                     self.current_area.at
                 ])
             else:
                 Narrator().add([self.name, 'drinks', self.current_area.at])
     else:
         water = random()
         amount = min(self.thirst, water)
         self._water += amount
         water -= amount
         for b in self.bottles:
             amount = min(1 - b.fill, water)
             b.fill += amount
             water -= amount
示例#6
0
 def _apply(self, name, player):
     if player.be_damaged(random() * 5, 'fire'):
         Narrator().new([player.name, 'blows up', 'on', f'{name}!'])
     else:
         Narrator().new([player.name, 'steps', 'on', f'{name}!'])
         if not Narrator().has_stock:
             Narrator().add([player.name, 'is', 'wounded'])
         Narrator().apply_stock()
示例#7
0
 def _apply(self, name, player):
     Narrator().new(
         [player.first_name, 'gets', 'ensnared into', f'{name}!'])
     if random() > 0.5:
         player.status.append('leg wound')
         Narrator().add([player.name, 'wounds', player.his, 'leg'])
     else:
         player.status.append(TRAPPED)
         take_advantage_of_trap(self, player)
示例#8
0
 def go_to_sleep(self, stock=False):
     if self.energy < 0.2:
         Narrator().add([self.name, 'is exhausted'], stock=stock)
     self.add_health(self.energy * (1 - self.health))
     self.add_energy(self.sleep * (1 - self.energy))
     self.add_sleep(1)
     verb = 'sleeps' if self.energy > 0 else 'collapses'
     Narrator().add([self.name, verb, self.current_area.at], stock=stock)
     self.status.append(SLEEPING)
示例#9
0
 def _apply(self, name, player):
     if player.be_damaged(random(), 'trident'):
         Narrator().new([
             player.name, 'impales', f'{player.him}self', 'on', f'{name}!'
         ])
     else:
         Narrator().new([player.name, 'falls', f'into', f'{name}!'])
         if not Narrator().has_stock:
             Narrator().add([player.name, 'is', 'lightly wounded'])
         Narrator().apply_stock()
示例#10
0
 def apply_strat(self, strategy: Optional[Strategy]):
     Narrator().cut()
     if self.acted or self.busy:
         return
     if strategy is None:
         strategy = self.strategy
     try:
         strategy.apply(self)
     except AttributeError as e:
         raise AttributeError(
             f'{self.name}({self.current_area.at}) has no strat ({self.strategy})'
         ) from e
     Narrator().cut()
示例#11
0
    def go_get_drop(self, area: Area):
        self.end_ambush()
        out = self.go_to(area)
        if out is not None:
            Narrator().add([self.name, f'goes {out.to} to get loot'])
        else:
            Narrator().cut()
        if self.check_for_ambush_and_traps():
            return
        seen_neighbors = [
            p for p in Map().potential_players(self)
            if self.can_see(p) and p != self
        ]
        free_neighbors = [
            p for p in seen_neighbors
            if p.current_area == self.current_area and not p.busy
        ]
        potential_danger = sum([p.dangerosity for p in seen_neighbors])
        actual_danger = sum([p.dangerosity for p in free_neighbors])

        if potential_danger > self.dangerosity and potential_danger > self.courage:
            Narrator().add([
                self.name, 'sees',
                format_list([p.name for p in seen_neighbors])
            ])
            self.flee(filtered_areas=[area])
        elif actual_danger > self.dangerosity and actual_danger > self.courage:
            Narrator().add([
                self.name, 'sees',
                format_list([p.name for p in free_neighbors])
            ])
            self.flee(filtered_areas=[area])
        elif actual_danger > 0:  # enemy present -> fight them
            Narrator().cut()
            self.attack_at_random()
        elif potential_danger > 0 and actual_danger == 0:  # enemy busy but incoming
            if self.dangerosity > potential_danger:  # attack before the other(s) arrive
                Narrator().cut()
                self.attack_at_random()
            else:  # loot and go/get your load and hit the road
                Narrator().add([
                    self.name, 'avoids',
                    format_list([p.name for p in seen_neighbors])
                ])
                self.loot(take_a_break=False)
                self.flee(filtered_areas=[area])
        else:  # servez-vous
            self.loot()
        if len(Narrator().current_sentence) == 0:
            Narrator().add([
                self.name,
                f'potential_danger={potential_danger}',
                f'actual_danger={actual_danger}',
                f'dangerosity={self.dangerosity}',
                f'courage={self.courage}',
            ])
示例#12
0
 def choose_between(self, player_a, player_b):
     p_a = self._ally_potential(player_a)
     p_b = self._ally_potential(player_b)
     if p_a > p_b and p_a > 0:
         Narrator().add([self.name, 'sides with', player_a.name])
         player_a.relationship(self).add_trust(0.25)
         self.new_ally(player_a)
     elif p_b > 0:
         Narrator().add([self.name, 'sides with', player_b.name])
         player_b.relationship(self).add_trust(0.25)
         self.new_ally(player_b)
     else:
         Narrator().add([self.name, 'chooses to go on', self.his, 'own'])
         if self.can_flee():
             self.flee()
示例#13
0
    def rest(self, stock=False):
        if self.current_area.name != START_AREA:
            self.stealth += random() * (1 - self.stealth)
            Narrator().add([self.name, 'hides', self.current_area.at], stock=stock)

        self.take_a_break()
        wounds = self.wounds
        if BLEEDING in wounds:
            self.patch(BLEEDING, stock=stock)
        elif len(wounds):
            self.patch(choice(wounds), stock=stock)
        else:
            self.add_health(max(self.energy, random()) * (self.max_health - self.health))
            self.add_energy(max(self.sleep, random()) * (1 - self.energy))
            Narrator().add([self.name, 'rests', self.current_area.at], stock=stock)
示例#14
0
 def trigger_event(self):
     possible_events = [cls for cls in self.event_classes if cls.can_happen()]
     if not len(possible_events):
         return
     self._event_gauge = 0
     event = choice(possible_events)()
     areas = format_list(list(set([f'the {area.name}' for area in event.areas])))
     Narrator().new(['EVENT:', event.name.upper(), f'at {areas}'])
     Narrator().new(['EVENT:', event.name.upper(), f'at {event.areas}'])
     Narrator().cut()
     event.trigger()
     Narrator().new(' ')
     Narrator().cut()
     self._players_at_last_event = len(self.alive_players)
     self._time_since_last_event = 0
示例#15
0
 def loot_bag(self, take_a_break=True):
     item = Map().pick_bag(self.current_area)
     if item is None:
         return self.loot(take_a_break=take_a_break)
     Narrator().add(
         [self.name, 'picks up', item.long_name, self.current_area.at])
     self.get_item(item)
示例#16
0
    def upkeep(self):
        self.destination = None
        self.stop_running()

        dehydratation = 0.5 if BURN_WOUND in self.status else 0.3
        self._water -= dehydratation
        self.water_upkeep()
        energy_upkeep = -random() * 0.1  # loses energy while being awake
        sleep_upkeep = max(random(), random()) * 0.1
        food_upkeep = max(random(), random()) * 0.2
        if self.thirst > 1:
            self.status.append(THIRSTY)
            energy_upkeep *= self.thirst
        if SLEEPING in self.status:
            self.status.remove(SLEEPING)
            sleep_upkeep = 0
            energy_upkeep = 0
            food_upkeep /= 2
        energy_upkeep += min(sleep_upkeep, self.sleep)  # compensates with sleep reserves
        energy_upkeep += min(food_upkeep, self.stomach)  # compensates with food reserves
        self.add_sleep(-sleep_upkeep * 2)  # consumes sleep reserves
        self.consume_nutriments(-food_upkeep)  # consumes food reserves
        self.add_energy(energy_upkeep + sleep_upkeep + food_upkeep)

        if BLEEDING in self.status:
            if self.be_damaged(max(0.05, self.health / 5)):
                Narrator().add([self.name, 'bleeds', 'to death'])
        for poison in self.active_poisons:
            poison.upkeep(self)
        self._rage = 0
示例#17
0
 def set_up_ambush(self):
     self.stealth += (random() / 2 + 0.5) * (1 - self.stealth)
     self.end_ambush()
     Map().add_ambusher(self, self)
     self._ambush = True
     Narrator().add(
         [self.name, 'sets up', 'an ambush', self.current_area.at])
示例#18
0
 def pillage(self, stuff):
     if len([p for p in Context().alive_players if p.is_alive]) == 1:
         return
     if Map().players_count(self) > 1:
         return
     looted = []
     for item in stuff:
         if item not in Map().loot(self.current_area):
             continue
         if isinstance(item, Weapon):
             if item.damage_mult > self.weapon.damage_mult:
                 looted.append(item)
                 Map().remove_loot(item, self.current_area)
         else:
             looted.append(item)
             Map().remove_loot(item, self.current_area)
     if not len(looted):
         return
     Narrator().add(
         [self.name, 'loots',
          format_list([e.long_name for e in looted])])
     for item in looted:
         if isinstance(item, Weapon):
             self.get_weapon(item)
         else:
             self.get_item(item)
示例#19
0
 def hit(self, target: LivingEntity, mult=1) -> bool:
     if SLEEPING in target.status:
         target.status.remove(SLEEPING)
         mult *= 2
     if self.energy < 0.1:
         mult /= 2
         self._rage = -1
     else:
         self.add_energy(-0.1)
     hit_chance = mult if mult > 1 else 0.6 * mult
     if ARM_WOUND in self.status:
         hit_chance -= 0.2
     if TRAPPED in target.status:
         hit_chance += 0.3
     if random() < hit_chance:
         self._rage += 0.1
         if self.weapon.poison is not None and\
                         self.weapon.poison.long_name not in [p.long_name for p in target.active_poisons]:
             if random() > 0.3:
                 target.add_poison(copy(self.weapon.poison))
             self.weapon.poison.amount -= 1
             if self.weapon.poison.amount == 0:
                 self.weapon.poison = None
         return target.be_damaged(self.damage() * mult,
                                  weapon=self.weapon.name,
                                  attacker_name=self.name)
     else:  # Miss
         self._rage -= 0.1
         Narrator().stock([self.name, 'misses'])
         return False
示例#20
0
    def flee(self,
             area=None,
             panic=False,
             drop_verb='drops',
             stock=False,
             filtered_areas=None):
        if area is None:
            if filtered_areas is None:
                filtered_areas = []
            filtered_areas = [*Context().forbidden_areas, *filtered_areas]
            self.status.append(FLEEING)
            if panic and random() > self.courage + 0.5:
                self.drop_weapon(verbose=True, drop_verb=drop_verb)

            available_areas = [
                area for area in Map().areas if area not in filtered_areas
            ]
            available_areas.sort(key=lambda x: self._flee_value(x))
            if available_areas:
                area = available_areas[-1]
        out = None
        self.reveal()
        if area is not None:
            out = self.go_to(area)
        if out is None:
            self.hide(panic=panic, stock=stock)
        else:
            Narrator().add([self.name, f'flees {out.to}'], stock=stock)
            self.check_for_ambush_and_traps()
示例#21
0
 def ask_to_ally(self, player):
     self.reveal()
     if random() < player.want_to_ally(self):
         Narrator().new([
             self.name, 'proposes', 'an alliance to', player.name, 'and',
             player.he, 'accepts!'
         ])
         self.new_ally(player)
         player.new_ally(self)
     else:
         Narrator().new([
             self.name, 'proposes', 'an alliance to', player.name, 'but',
             player.he, 'refuses'
         ])
         self.relationship(player).add_friendship(-0.5)
         self.relationship(player).add_trust(-2)
         self.relationship(player).add_trust(1)  # trust = 0
示例#22
0
 def eat(self, food: Food, quantifier='', verbose=True):
     if verbose:
         Narrator().add([
             self.name, 'eats', quantifier, food.name, self.current_area.at
         ])
     self.consume_nutriments(food.value)
     if food.is_poisonous:
         self._poisons.append(copy(food.poison))
         while food in self.equipment:
             self.remove_item(food)
         if verbose:
             Narrator().new([
                 f'The {food.name}',
                 'are' if food.name[-1] == 's' else 'is', 'poisonous!'
             ])
             Narrator().cut()
         return 'poison'
示例#23
0
    def loot_weapon(self,
                    weapon: Optional[Union[Weapon, List[Weapon]]] = None):
        weapons: List[Weapon] = []
        if isinstance(weapon, Weapon):
            weapons.append(weapon)
        if isinstance(weapon, list):
            weapons = weapon
        if weapon is None:
            for _ in self.acting_players:
                weapons.append(Map().pick_weapon(self))
        weapons = [w for w in weapons if w is not None]

        weapons.sort(key=lambda x: -x.damage_mult)
        self.acting_players.sort(key=lambda x: -x.weapon.damage_mult)

        empty_handed: List[Player] = []
        for player in self.acting_players:
            picked = False
            for weapon in weapons:
                if weapon.damage_mult > player.weapon.damage_mult:
                    if weapon.name == player.weapon.name:
                        player.weapon.long_name.replace('\'s', '\'s old')
                        Narrator().add([
                            player.name, 'picks up', f'a better {weapon.name}',
                            self.current_area.at
                        ])
                    else:
                        Narrator().add([
                            player.name, 'picks up', weapon.long_name,
                            self.current_area.at
                        ])
                    if player.weapon != HANDS:
                        weapons.append(player.weapon)
                    player.get_weapon(weapon)
                    weapons.remove(weapon)
                    picked = True
                    break
            if not picked:
                empty_handed.append(player)
        if len(empty_handed):
            verb = 'try' if len(empty_handed) > 1 else 'tries'
            Narrator().add([
                player_names(empty_handed), verb, 'to find weapons',
                self.current_area.at, 'but can\'t find anything good'
            ])
示例#24
0
 def upkeep(self, player: LivingEntity):
     if self.amount == 0:
         player.remove_poison(self)
         return
     self.amount -= 1
     live = player.is_alive
     player.add_health(-self.damage)
     if live and not player.is_alive:
         Narrator().new([player.name, 'succumbs', 'to', self.long_name])
示例#25
0
 def set_up_ambush(self):
     self.stealth += (random() / 2 + 0.5) * (1 - self.stealth)
     if AMBUSH not in self.status:
         self.status.append(AMBUSH)
         Map().add_ambusher(self, self)
         Narrator().add(
             [self.name, 'sets up', 'an ambush', self.current_area.at])
     else:
         self._waiting += 1
         if self._waiting < 2:
             Narrator().add(
                 [self.name, 'keeps', 'hiding', self.current_area.at])
         else:
             Narrator().add([
                 self.name, 'gets', 'tired of hiding', self.current_area.at
             ])
             self.end_ambush()
             self.pursue()
示例#26
0
 def death(self, dead_player):
     try:
         self.map.remove_player(dead_player)
     except ValueError as e:
         Narrator().tell()
         raise ValueError(
             f'{dead_player.name} has {dead_player.health}hp, is_alive={dead_player.is_alive}, '
             f'is_in_players={dead_player in self.alive_players}'
         ) from e
示例#27
0
 def drop_weapon(self, verbose=True, drop_verb='drops'):
     if self.weapon != HANDS:
         if verbose:
             Narrator().add([
                 self.name, drop_verb, f'{self.his} {self.weapon.name}',
                 self.current_area.at
             ])
         Map().add_loot(self.weapon, self.current_area)
     self._weapon = HANDS
示例#28
0
 def hide(self, panic=False, stock=False):
     if panic:
         Narrator().add([
             player_names(self.acting_players), 'hides',
             self.current_area.at
         ],
                        stock=stock)
         return
     for player in self.acting_players:
         player.hide(stock=stock)
示例#29
0
def build_trap(player, trap_class: Type[Trap]):
    player.reveal()
    if not trap_class.can_be_built(player):
        return
    for ingredient in trap_class.ingredients:
        item = [i for i in player.equipment if i.name == ingredient][0]
        player.remove_item(item)
    trap = trap_class(player, random() / 2 + 0.5)
    Narrator().add(
        [player.name, 'builds', 'a', trap.name, f'at {player.current_area}'])
示例#30
0
    def dine(self):
        self.take_a_break()
        food_owner: Dict[Food, Player] = {}
        for player in self.acting_players:
            for e in player.equipment:
                if isinstance(e, Food):
                    food_owner[e] = player
        if not len(food_owner):
            Narrator().add([self.name, 'does not have', 'anything to eat'])
        else:
            food = list(food_owner.keys())
            food.sort(key=lambda x: x.value)
            diner = {p: [] for p in self.acting_players}
            poison = {p: None for p in self.acting_players}
            eaters = copy(self.acting_players)
            eaters.sort(key=lambda x: -x.hunger)
            while len(eaters) and len(food):
                eaters_this_round = copy(eaters)
                for eater in eaters_this_round:
                    try:
                        meal = food.pop()
                    except IndexError:
                        break
                    food_owner[meal].remove_item(meal)
                    diner[eater].append(meal.name)
                    if eater.eat(meal, verbose=False) == 'poison':
                        poison[eater] = meal
                        eaters.remove(eater)
                    elif not eater.hunger:
                        eaters.remove(eater)

            for player in self.acting_players:
                if len(diner[player]):
                    Narrator().add([
                        player.name, 'eats', player.his,
                        format_list(diner[player]), self.current_area.at
                    ])
                    if poison[player] is not None:
                        Narrator().new(
                            [f'the {poison[player].name}', 'is', 'poisonous!'])
                        Narrator().cut()
                    player.consume_antidote()