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}', ])
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)
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])
def run(self): self.day = 1 self._event_gauge = 0 self._players_at_last_event = len(self.alive_players) self._time_since_last_event = 0 Narrator().new(f'== DAY {self.day} START ==') Narrator().new(['All players start', self.map.get_area(START_AREA).at]) self.time = STARTER Context().forbidden_areas.append(self.map.get_area(START_AREA)) rounds = 0 while len(self.playing_entities_at(self.map.get_area(START_AREA))) > 1: Narrator().tell() self.launch() Narrator().tell(filters=[self.map.get_area(START_AREA).at]) Narrator().new(f'...') if self.map.players_count(START_AREA) > 1: Narrator().new([ format_list([p.name for p in self.alive_players if p.current_area.is_start]), 'remain', self.map.get_area(START_AREA).at ]) elif self.map.players_count(START_AREA) == 1: Narrator().new([ 'Only', [p for p in self.alive_players if p.current_area.is_start][0].name, 'remains', self.map.get_area(START_AREA).at ]) Narrator().tell() self.launch() Narrator().tell(filters=[self.map.get_area(START_AREA).at]) rounds += 1 if rounds > 10: raise Exception self._players_at_last_event = len(self.alive_players) while len(self.alive_players) > 1 and self.day < 10: if self.day != 1: self.time = MORNING self.launch() if len(self.alive_players) < 2: break Narrator().new(f'-- DAY {self.day} afternoon --') self.time = AFTERNOON self.launch() if len(self.alive_players) < 2: break Narrator().new(f'-- NIGHT {self.day} --') self.time = NIGHT self.launch() if len(self.alive_players) < 2: break Narrator().tell() self.status() self.day += 1 Narrator().new(f'\n== DAY {self.day} morning ==') if len(self.alive_players) == 1: Narrator().tell() print(f'{self.alive_players[0].name} wins the Hunger Games!')
def patch(self, wound: str, stock=False): verbs = [] tools = [] if self.has_item('iodine'): self.remove_item('iodine') verbs = ['disinfects'] tools = ['iodine'] elif Map().has_water(self): self._max_health *= 0.99 verbs = ['cleans'] tools = [f'{self.current_area}\'s water'] elif sum([b.fill for b in self.bottles]) > 0.2: self.use_water(0.2) self._max_health *= 0.99 verbs = ['cleans'] tools = ['water'] else: self._max_health *= 0.95 verbs.append('stops' if wound == BLEEDING else 'patches') verb_part_2 = 'from bleeding' if wound == BLEEDING else '' if self.has_item('bandages'): self.remove_item('bandages') tools.append('bandages') else: self._max_health *= 0.95 tools.append(choice(['moss', 'cloth'])) wound_name = 'wounds' if wound == BLEEDING else wound Narrator().add([ self.name, format_list(verbs), self.his, wound_name, verb_part_2, 'using', format_list(tools) ], stock=stock) self.status.remove(wound)
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
def trigger(self): Context().forbidden_areas.extend(self.areas) saw_it_coming = [] warned = [] # Narrator().add(['should trigger for', [p.name for a in self.areas for p in a.players]]) for area in self.areas: for p_e in Context().playing_entities_at(area): for p in p_e.players: if p.wisdom * random() > self.stealth: saw_it_coming.append(p.name) warned.extend(p_e.players) break if len(saw_it_coming): Narrator().new([ format_list(saw_it_coming), 'see' if len(saw_it_coming) > 1 else 'sees', self.it, 'coming' ]) for area in self.areas: area_players = copy(area.players) for p in area_players: Narrator().cut() if p.can_flee(): if p in warned: p.flee() if p.current_area in self.areas: Narrator().new([ 'error:', 'forbidden:', Context().forbidden_areas, p.name, p.current_area.at]) Map().test = 'SHIT' elif p.be_damaged(self.base_damage, weapon=self.weapon_name): Narrator().new([p.name, 'fails', 'to escape', self.it, 'and', self.dies, area.at]) else: Narrator().apply_stock() p.flee(panic=True, drop_verb='loses') continue # successful escape Narrator().new([p.name, 'is', 'trapped', area.at]) if self.trapped_means_dead: p.be_damaged(1) Narrator().add([p.name, 'is', 'swiped', 'by', self.it, area.at, 'and', self.dies]) elif p.be_damaged(random() * self.extra_damage + self.base_damage, weapon=self.weapon_name): Narrator().add(['and', self.dies]) else: Narrator().apply_stock() if not len(Narrator().current_sentence): # error Narrator().add([p.name, 'escaped', self.it, 'and is', p.current_area.at]) Narrator().clear_stock() if self.remove_loot: area.loot.clear()
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()
def pursue(self): available_areas = [ a for a in Map().areas if a not in Context().forbidden_areas ] available_areas.sort( key=lambda x: sum(p._pursue_value(x) for p in self.acting_players)) out = None if not available_areas: out = self.go_to(available_areas[-1]) if out is None: self.hide() Narrator().replace('hides and rests', 'rests') else: targets = [ p.name for p in Context().alive_players if p not in self.players ] players = 'players' if len(targets) > 2 else format_list(targets) Narrator().add([self.name, 'searches for', players, out.at]) self.check_for_ambush_and_traps()
def trigger(self): possible_loots = [ Food(choice(['ration', 'food can', 'energy bar']), 0.75), Food(choice(['ration', 'food can', 'energy bar']), 0.50), Food(choice(['ration', 'food can', 'energy bar']), 0.25), Item('bandages'), Item('iodine'), Item('antidote'), Bottle(1), Weapon(choice([SWORD, AXE, MACE]), 2 + random()) ] possible_loots = [i for i in possible_loots if sum(p.estimate(i) for p in Context().alive_players)] possible_loots.sort(key=lambda x: -sum(p.estimate(x) for p in Context().alive_players)) area = self.areas[0] nb_bags = randint(1, len(Context().alive_players) - 1) while nb_bags > len(possible_loots): possible_loots.extend(possible_loots) bags = [] for i in range(nb_bags): bags.append(Bag([possible_loots[i], possible_loots[-(i + 1)]])) for bag in bags: Map().add_loot(bag, area) verb = 'have' if nb_bags > 1 else 'has' Narrator().new([nb_bags, 'bag' + ('s' if nb_bags > 1 else ''), verb, 'been dropped', area.at]) Narrator().new([ 'The bag' + ('s' if nb_bags > 1 else ''), 'contain' + ('s' if nb_bags == 1 else ''), format_list([i.name for b in bags for i in b.content])])
def dine(self): self.take_a_break() if not self.has_food: Narrator().add([self.name, 'does not have', 'anything to eat']) else: foods = [e for e in self.equipment if isinstance(e, Food)] foods.sort(key=lambda x: x.value) diner = [] poison = None while self.hunger > 0 and len(foods): meal = foods.pop() self.remove_item(meal) diner.append(meal.name) if self.eat(meal, verbose=False) == 'poison': poison = meal break Narrator().add([ self.name, 'eats', self.his, format_list(diner), self.current_area.at ]) if poison is not None: Narrator().new([f'the {poison.name}', 'is', 'poisonous!']) Narrator().cut() self.consume_antidote()
def player_names(players: List[Player]) -> str: return format_list([p.name for p in players])
def describe_allies(self): return format_list([p.name for p in self.allies()])
def full_status_desc(self): return format_list([*self.status, *[str(p) for p in self._poisons]])