diff --git a/pokete.py b/pokete.py index c73a9f04..8836b351 100755 --- a/pokete.py +++ b/pokete.py @@ -27,6 +27,7 @@ from pokete_classes.settings import settings, VisSetting from pokete_classes.inv_items import invitems, LearnDisc from pokete_classes.types import types +from pokete_classes.providers import ProtoFigure from pokete_classes.buy import Buy from pokete_classes.side_loops import ResizeScreen, LoadingScreen, About, Help from pokete_classes.input import text_input, ask_bool, ask_text, ask_ok @@ -353,7 +354,7 @@ def __init__(self, _he, _wi): self.interact.add(self, int(self.width / 2), 4) -class Figure(se.Object): +class Figure(se.Object, ProtoFigure): """The figure that moves around on the map and represents the player ARGS: _si: session_info dict""" @@ -365,11 +366,13 @@ def __init__(self, _si): "[Figure] '%s' is no valid 'represent_char', resetting", r_char) r_char = "a" super().__init__(r_char, state="solid") + ProtoFigure.__init__( + self, + [Poke.from_dict(_si["pokes"][poke]) for poke in _si["pokes"]] + ) self.__money = _si.get("money", 10) self.inv = _si.get("inv", {"poketeballs": 10}) self.name = _si.get("user", "DEFAULT") - self.pokes = [Poke.from_dict(_si["pokes"][poke]) - for poke in _si["pokes"]] self.caught_pokes = _si.get("caught_poketes", []) self.visited_maps = _si.get("visited_maps", ["playmap_1"]) self.used_npcs = _si.get("used_npcs", []) @@ -378,6 +381,13 @@ def __init__(self, _si): self.oldmap = obmp.ob_maps[_si.get("oldmap", "playmap_1")] self.direction = "t" + def get_attack(self, fightmap, enem): + """Returns the choosen attack: + ARGS: + fightmap: fightmap object + anem: The enemy Provider""" + return fightmap.get_figure_attack(self, enem) + def set_args(self, _si): """Processes data from save file ARGS: @@ -806,12 +816,13 @@ def reset_terminal(): termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) -def exiter(): +def exiter(end=False): """Exit function""" reset_terminal() logging.info("[General] Exiting...") print("\033[?1049l\033[1A") - sys.exit() + if not end: + sys.exit() # Functions needed for mvp.movemap @@ -1082,7 +1093,7 @@ def gen_obs(): _map = obmp.ob_maps[i] for j in trainers[i]: args = j["args"] - trainer = Trainer(Poke(*j["poke"], player=False), *args[:-2]) + trainer = Trainer([Poke(*p, player=False) for p in j["pokes"]], *args[:-2]) trainer.add(_map, args[-2], args[-1]) _map.trainers.append(trainer) @@ -1355,6 +1366,7 @@ def map_additions(): _map.dor.add(_map, 44, 52) _map.shopdor.add(_map, 122, 64) + # Actual code execution ####################### if __name__ == "__main__": @@ -1495,9 +1507,7 @@ def recogniser(): achievements.add(identifier, **args) # objects relevant for fm.fight() - fm.fight = fm.Fight(figure) fm.fightmap = fm.FightMap(height - 1, width) - fm.fightitems = fm.FightItems(figure) for _i in [NPC, Trainer]: _i.set_vars(figure, NPCActions) @@ -1514,3 +1524,5 @@ def recogniser(): main() except KeyboardInterrupt: print("\033[?1049l\033[1A\nKeyboardInterrupt") + finally: + exiter(True) diff --git a/pokete_classes/fightmap.py b/pokete_classes/fightmap.py index b2499285..c38ad22a 100644 --- a/pokete_classes/fightmap.py +++ b/pokete_classes/fightmap.py @@ -8,6 +8,8 @@ from pokete_classes import animations, ob_maps as obmp, movemap as mvp, \ deck, game_map as gm from .loops import std_loop +from .npcs import Trainer +from .providers import NatureProvider, ProtoFigure from .ui_elements import StdFrame2, ChooseBox from .classes import OutP from .input import ask_bool @@ -61,79 +63,80 @@ def __init__(self, height, width): self.height - 9) self.frame_small.add(self, 0, self.height - 5) self.label.add(self, 0, self.height - 1) - self.figure = None - def clean_up(self, player, enemy): + def clean_up(self, *providers): """Removes all labels from self ARGS: - player: The player Poke object - enemy: The enemy Poke object + providers: The Providers to clean up that the labels belong to""" - for obj in [enemy.text_name, enemy.text_lvl, enemy.text_hp, enemy.ico, - enemy.hp_bar, enemy.tril, enemy.trir, player.text_name, - player.text_lvl, player.text_hp, player.ico, player.hp_bar, - player.tril, player.trir, enemy.pball_small]: - obj.remove() - self.box.remove_c_obs() - for i in [player, enemy]: - for j in i.effects: + for prov in providers: + for obj in ( + prov.curr.text_name, prov.curr.text_lvl, prov.curr.text_hp, + prov.curr.ico, prov.curr.hp_bar, prov.curr.tril, prov.curr.trir, + prov.curr.pball_small + ): + obj.remove() + if isinstance(prov, ProtoFigure): + self.box.remove_c_obs() + for j in prov.curr.effects: j.cleanup() - def add_3(self, player, enemy): + def add_player(self, player): """Adds player labels ARGS: - player: The player Poke object - enemy: The enemy Poke object - that the labels belong to""" - if player.identifier != "__fallback__": - player.text_name.add(self, self.width - 17, self.height - 9) - player.text_lvl.add(self, self.width - 17, self.height - 8) - player.tril.add(self, self.width - 11, self.height - 7) - player.trir.add(self, self.width - 2, self.height - 7) - player.hp_bar.add(self, self.width - 10, self.height - 7) - player.text_hp.add(self, self.width - 17, self.height - 7) - player.ico.add(self, 3, self.height - 10) - return [player, enemy] - - def add_1(self, player, enemy, caught_poketes): + player: The player Poke object""" + player.curr.text_name.add(self, self.width - 17, self.height - 9) + player.curr.text_lvl.add(self, self.width - 17, self.height - 8) + player.curr.tril.add(self, self.width - 11, self.height - 7) + player.curr.trir.add(self, self.width - 2, self.height - 7) + player.curr.hp_bar.add(self, self.width - 10, self.height - 7) + player.curr.text_hp.add(self, self.width - 17, self.height - 7) + player.curr.ico.add(self, 3, self.height - 10) + self.box.add_c_obs([atc.label for atc in player.curr.attack_obs]) + self.box.set_index(0) + + def add_1(self, player, enem): """Adds enemy and general labels to self ARGS: player: The player Poke object - enemy: The enemy Poke object - that the labels belong to - caught_poketes: List of Poke.identifiers of Pokes that have already - been caught""" - for obj, x, y in zip([enemy.tril, enemy.trir, - enemy.text_name, enemy.text_lvl, - enemy.text_hp, enemy.ico, enemy.hp_bar], - [7, 16, 1, 1, 1, self.width - 14, 8], - [3, 3, 1, 2, 3, 2, 3]): + enemy: The enemy Poke object that the labels belong to""" + for obj, x, y in zip( + ( + enem.curr.tril, + enem.curr.trir, + enem.curr.text_name, + enem.curr.text_lvl, + enem.curr.text_hp, + enem.curr.ico, + enem.curr.hp_bar + ), + (7, 16, 1, 1, 1, self.width - 14, 8), + (3, 3, 1, 2, 3, 2, 3) + ): obj.add(self, x, y) - if enemy.identifier in caught_poketes: - enemy.pball_small.add(self, len(self.e_underline.text) - 1, 1) - if player.identifier != "__fallback__": - self.box.add_c_obs([atc.label for atc in player.attack_obs]) - self.box.set_index(0) - return [player, enemy] + if enem.curr.identifier in player.caught_pokes: + enem.curr.pball_small.add(self, len(self.e_underline.text) - 1, 1) + def add_2(self, player): """Adds player labels with sleeps ARGS: player: The player Poke object that the labels belong to""" - if player.identifier != "__fallback__": - player.text_name.add(self, self.width - 17, self.height - 9) - time.sleep(0.05) - self.show() - player.text_lvl.add(self, self.width - 17, self.height - 8) - time.sleep(0.05) - self.show() - player.tril.add(self, self.width - 11, self.height - 7) - player.trir.add(self, self.width - 2, self.height - 7) - player.hp_bar.add(self, self.width - 10, self.height - 7) - player.text_hp.add(self, self.width - 17, self.height - 7) - time.sleep(0.05) - self.show() - player.ico.add(self, 3, self.height - 10) + player.curr.text_name.add(self, self.width - 17, self.height - 9) + time.sleep(0.05) + self.show() + player.curr.text_lvl.add(self, self.width - 17, self.height - 8) + time.sleep(0.05) + self.show() + player.curr.tril.add(self, self.width - 11, self.height - 7) + player.curr.trir.add(self, self.width - 2, self.height - 7) + player.curr.hp_bar.add(self, self.width - 10, self.height - 7) + player.curr.text_hp.add(self, self.width - 17, self.height - 7) + time.sleep(0.05) + self.show() + player.curr.ico.add(self, 3, self.height - 10) + self.box.add_c_obs([atc.label for atc in player.curr.attack_obs]) + self.box.set_index(0) def fast_change(self, arr, setob): """Changes fast between a list of texts @@ -152,7 +155,7 @@ def get_attack(self, attack_obs): ARGS: attack_obs: A list of Attack objects that belong to a Poke""" with self.box.add(self, 1, self.height - 7): - while True: + while True:#158 if _ev.get() in ["'s'", "'w'"]: self.box.input(_ev.get()) self.show() @@ -197,226 +200,234 @@ def get_item(self, items, inv): self.invbox.remove_c_obs() return item - def fight(self, player, enemy, figure, info): + def get_figure_attack(self, figure, enem): + """Chooses the players attack + ARGS: + figure: The players provider + enem: The enemys provider""" + self.outp.append(se.Text(("\n" if "\n" not in self.outp.text + else "") + + "What do you want to do?", + state="float")) + while True: # Inputloop for general options + if _ev.get() == "'1'": + _ev.clear() + attack = self.get_attack(figure.curr.attack_obs) + if attack != "": + return attack + elif _ev.get() == "'2'": + _ev.clear() + if ( + type(enem) is Trainer + or not ask_bool(self, "Do you really want to run away?") + ): + continue + if (random.randint(0, 100) < max(5, min(50 - (figure.curr.initiative - enem.curr.initiative), 95))): + self.outp.outp("You failed to run away!") + time.sleep(1) + return "" + self.outp.outp("You ran away!") + time.sleep(1) + self.clean_up(figure, enem) + logging.info("[Fight] Ended, ran away") + return "won" + elif _ev.get() == "'3'": + _ev.clear() + items = [getattr(invitems, i) + for i in figure.inv + if getattr(invitems, i).fn is not None + and figure.inv[i] > 0] + if not items: + self.outp.outp( + "You don't have any items left!\n" + "What do you want to do?" + ) + continue + item = self.get_item(items, figure.inv) + if item == "": + continue + # I hate you python for not having switch statements + if (i := getattr(fightitems, item.fn)(figure, enem)) == 1: + continue + elif i == 2: + logging.info("[Fight] Ended, fightitem") + return "won" + return "" + elif _ev.get() == "'4'": + _ev.clear() + if not self.choose_poke(figure): + self.show(init=True) + continue + return "" + std_loop(False) + + def fight(self, providers): """Fight between two Pokes ARGS: - player: The players' used Poke - enemy: The enemy's used Poke - figure: Figure object - info: Dict with information about the fight - ({"type": "wild", "player": " "}) + providers RETURNS: - Poke object that won the fight""" - self.figure = figure - logging.info("[Fight][%s] Started between %s(player) lvl.%d and \ -%s(enemy) lvl.%d", info["type"], player.name, player.lvl(), enemy.name, - enemy.lvl()) + Provider that won the fight""" + index = 0 + logging.info( + "[Fight] Started between %s", + "and ".join( + f"{prov.curr.name} ({type(prov)}) lvl. {prov.curr.lvl()}" + for prov in providers + ) + ) + weather = providers[0].map.weather + for prov in providers: + prov.index_conf() if settings("animations").val: # Intro animation animations.fight_intro(self.height, self.width) - players = self.add_1(player, enemy, figure.caught_pokes) - if info["type"] == "wild": - self.outp.outp(f"A wild {enemy.name} appeared!") - elif info["type"] == "duel": - self.outp.outp(f"{info['player'].name} started a fight!") - time.sleep(1) - self.outp.outp(f'{self.outp.text}\n{info["player"].gender} \ -used {enemy.name} against you!') + self.add_1(*providers) + for prov in providers: + if type(prov) is NatureProvider: + self.outp.outp(f"A wild {prov.curr.name} appeared!") + elif type(prov) is Trainer: + self.outp.outp(f"{prov.name} started a fight!") + time.sleep(1) + self.outp.outp( + f'{self.outp.text}\n{prov.gender} used {prov.curr.name} ' + 'against you!' + ) time.sleep(1) - self.add_2(player) - if player.identifier != "__fallback__": - self.fast_change([player.ico, self.deadico2, self.deadico1, - player.ico], player.ico) - self.outp.outp(f"You used {player.name}") + self.add_2(providers[0]) + self.fast_change([providers[0].curr.ico, self.deadico2, self.deadico1, + providers[0].curr.ico], providers[0].curr.ico) + self.outp.outp(f"You used {providers[0].curr.name}") self.show() time.sleep(0.5) - if player.identifier == "__fallback__": - obj, enem = players - else: - enem = sorted(zip([i.initiative for i in players], - # The [1, 0] array is needed to avoid comparing - # two Poke objects - [1, 0], players))[0][-1] - obj = [i for i in players if i != enem][-1] - for i in players: + index = providers.index( + max(providers, key=lambda i: i.curr.initiative) + ) + for prov in providers: + i = prov.curr for j in i.effects: j.readd() while True: - if obj.player: - self.outp.append(se.Text(("\n" if "\n" not in self.outp.text - else "") + - "What do you want to do?", - state="float")) - if obj.identifier == "__fallback__": - time.sleep(1) - self.outp.outp("You don't have any living poketes left!") - while True: # Inputloop for general options - if _ev.get() == "'1'": - _ev.clear() - if player.identifier == "__fallback__": - continue - attack = self.get_attack(obj.attack_obs) - if attack != "": - break - elif _ev.get() == "'2'": - _ev.clear() - if ((info["type"] == "duel" - and player.identifier != "__fallback__") - or not ask_bool(self, - "Do you really want to run away?")): - continue - if (random.randint(0, 100) < max(5, min(50 - (player.initiative - enemy.initiative), 95))): - self.outp.outp("You failed to run away!") - time.sleep(1) - attack = "" - break - self.outp.outp("You ran away!") - time.sleep(1) - self.clean_up(player, enemy) - logging.info("[Fight][%s] Ended, ran away", - info["type"]) - return enem - elif _ev.get() == "'3'": - _ev.clear() - items = [getattr(invitems, i) - for i in figure.inv - if getattr(invitems, i).fn is not None - and figure.inv[i] > 0] - if not items: - self.outp.outp("You don't have any items left!\n\ - What do you want to do?") - continue - item = self.get_item(items, figure.inv) - if item == "": - continue - # I hate you python for not having switch statements - if (i := getattr(fightitems, item.fn)(obj, enem, info))\ - == 1: - continue - elif i == 2: - logging.info("[Fight][%s] Ended, fightitem", - info["type"]) - return obj - attack = "" - break - elif _ev.get() == "'4'": - _ev.clear() - if obj.identifier == "__fallback__": - continue - players, player = self.choose_poke(figure, players, player, enemy) - attack = "" - break - std_loop(False) - else: - attack = random.choices(obj.attack_obs, - weights=[i.ap * ((1.5 - if enem.type.name in - i.type.effective - else 0.5 - if enem.type.name in - i.type.ineffective - else 1) - if info["type"] == "duel" - else 1) - for i in obj.attack_obs])[0] + player = providers[index % 2] + enem = providers[(index + 1) % 2] + + attack = player.get_attack(self, enem) time.sleep(0.3) - if attack != "": - obj.attack(attack, enem, self) + if attack == "won": + return player + elif attack != "": + player.curr.attack(attack, enem.curr, self, weather) self.show() time.sleep(0.5) winner = None - if any(i.hp <= 0 for i in players): - winner = [i for i in players if i.hp > 0][0] - elif all(i.ap == 0 for i in obj.attack_obs): - winner = [i for i in players if i != obj][0] + loser = None + for i, prov in enumerate(providers): + if prov.curr.hp <= 0: + loser = prov + winner = providers[(i + 1) % 2] + if all(i.ap == 0 for i in player.curr.attack_obs): + winner = providers[(index + 1) % 2] time.sleep(2) - self.outp.outp(f"{obj.ext_name} has used all its' attacks!") + self.outp.outp(f"{player.curr.ext_name} has used all its' attacks!") time.sleep(3) if winner is not None: - if (obj.identifier != "__fallback__" - and not winner.player - and any(p.hp > 0 for p in figure.pokes[:6]) - and ask_bool(self, - "Do you want to choose another Pokete?")): - old_player = player - players, player = self.choose_poke(figure, players, - player, enemy) - if old_player == player: + if ( + loser.curr.player + and any(p.hp > 0 for p in loser.pokes[:6]) + and ask_bool(self, "Do you want to choose another Pokete?") + ): + success = self.choose_poke(loser) + if not success: break + elif ( + isinstance(loser, Trainer) + and winner.curr.player + and any(p.hp > 0 for p in loser.pokes) + ): + time.sleep(1) + ico = loser.curr.ico + self.fast_change([ico, self.deadico1, self.deadico2], ico) + self.deadico2.remove() + self.show() + self.clean_up(loser) + loser.play_index += 1 + self.add_1(*providers) + ico = loser.curr.ico + self.fast_change( + [ico, self.deadico2, self.deadico1, ico], ico + ) + self.outp.outp(f"{loser.name} used {loser.curr.name}!") + self.show() + time.sleep(2) else: break - obj = [i for i in players if i != obj][-1] - enem = [i for i in players if i != obj][-1] - loser = [obj for obj in players if obj != winner][0] - _xp = (loser.lose_xp + (1 if loser.lvl() > winner.lvl() else 0))\ - * (2 if info["type"] == "duel" else 1) - self.outp.outp(f"{winner.ext_name} won!" + (f'\nXP + {_xp}' - if winner.player else '')) - if winner.player and info["type"] == "duel": + index += 1 + # loser = [obj for obj in players if obj != winner][0] + _xp = sum( + poke.lose_xp + max(0, poke.lvl() - winner.curr.lvl()) + for poke in loser.pokes + ) * (2 if not isinstance(loser, NatureProvider) else 1) + self.outp.outp( + f"{winner.curr.ext_name} won!" + + (f'\nXP + {_xp}' if winner.curr.player else '') + ) + if winner.curr.player and isinstance(loser, Trainer): achievements.achieve("first_duel") - if winner.player and winner.add_xp(_xp): + if winner.curr.player and winner.curr.add_xp(_xp): time.sleep(1) - self.outp.outp(f"{winner.name} reached lvl {winner.lvl()}!") + self.outp.outp( + f"{winner.curr.name} reached lvl {winner.curr.lvl()}!" + ) winner.moves.shine() time.sleep(0.5) - winner.set_vars() - winner.learn_attack(self) - winner.evolve(figure, self) + winner.curr.set_vars() + winner.curr.learn_attack(self) + winner.curr.evolve(winner, self) self.show() time.sleep(1) - ico = [obj for obj in players if obj != winner][0].ico + ico = loser.curr.ico self.fast_change([ico, self.deadico1, self.deadico2], ico) self.deadico2.remove() self.show() - self.clean_up(player, enemy) - mvp.movemap.balls_label_rechar(figure.pokes) - logging.info("[Fight][%s] Ended, %s(%s) won", info["type"], - winner.name, "player" if winner.player else "enemy") + self.clean_up(*providers) + mvp.movemap.balls_label_rechar(winner.pokes) + logging.info( + "[Fight] Ended, %s(%s) won", + winner.curr.name, "player" if winner.curr.player else "enemy" + ) return winner - def choose_poke(self, figure, players, player, enemy): + def choose_poke(self, player): """Lets the player choose another Pokete from their deck ARGS: - figure: Figure object - players: The list of both player end enemy player: The players' used Poke - enemy: The enemy's used Poke RETURNS: - players: The list of both player end enemy - player: The players' used Poke""" - self.clean_up(player, enemy) + bool whether or not a Pokete was choosen""" + self.clean_up(player) index = deck.deck(6, "Your deck", True) - player = player if index is None else figure.pokes[index] - self.add_1(player, enemy, figure.caught_pokes) - self.box.set_index(0) - players = self.add_3(player, enemy) - self.outp.outp(f"You have choosen {player.name}") - for i in players: - for j in i.effects: - time.sleep(1) - j.readd() - return players, player + if index is not None: + player.play_index = index + self.add_player(player) + self.outp.outp(f"You have choosen {player.curr.name}") + for j in player.curr.effects: + time.sleep(1) + j.readd() + if index is None: + return False + return True class FightItems: """Contains all fns callable by an item in fight - ARGS: - figure: Figure object - The methods that can actually be called in fight follow the following pattern: ARGS: - obj: The players Poke object - enem: The enemys Poke object - info: The info dict + obj: The players Provider + enem: The enemys Provider RETURNS: 1: To continue the attack round 2: To win the game None: To let the enemy attack""" - def __init__(self, figure): - self.fig = figure - - def throw(self, obj, enem, info, chance, name): - """Throws a *ball + def throw(self, obj, enem, chance, name): + """Throws a ball ARGS: obj: The players Poke object enem: The enemys Poke object @@ -428,105 +439,83 @@ def throw(self, obj, enem, info, chance, name): 2: The win the game None: To let the enemy attack""" - if obj.identifier == "__fallback__" or info["type"] == "duel": + if not isinstance(enem, NatureProvider): + fightmap.outp.outp("You can't do that in a duel!") return 1 fightmap.outp.rechar(f"You threw a {name.capitalize()}!") - fightmap.fast_change([enem.ico, fightmap.deadico1, fightmap.deadico2, - fightmap.pball], enem.ico) + fightmap.fast_change([enem.curr.ico, fightmap.deadico1, fightmap.deadico2, + fightmap.pball], enem.curr.ico) time.sleep(random.choice([1, 2, 3, 4])) - self.fig.remove_item(name) - catch_chance = 20 if self.fig.map == obmp.ob_maps["playmap_1"] else 0 - for effect in enem.effects: + obj.remove_item(name) + catch_chance = 20 if obj.map == obmp.ob_maps["playmap_1"] else 0 + for effect in enem.curr.effects: catch_chance += effect.catch_chance if random.choices([True, False], - weights=[(enem.full_hp / enem.hp) + weights=[(enem.curr.full_hp / enem.curr.hp) * chance + catch_chance, - enem.full_hp], k=1)[0]: - self.fig.add_poke(enem) - fightmap.outp.outp(f"You caught {enem.name}!") + enem.curr.full_hp], k=1)[0]: + obj.add_poke(enem.curr) + fightmap.outp.outp(f"You caught {enem.curr.name}!") time.sleep(2) fightmap.pball.remove() fightmap.clean_up(obj, enem) - mvp.movemap.balls_label_rechar(self.fig.pokes) - logging.info("[Fighitem][%s] Caught %s", name, enem.name) + mvp.movemap.balls_label_rechar(obj.pokes) + logging.info("[Fighitem][%s] Caught %s", name, enem.curr.name) achievements.achieve("first_poke") - if all(poke in self.fig.caught_pokes for poke in p_data.pokes): + if all(poke in obj.caught_pokes for poke in p_data.pokes): achievements.achieve("catch_em_all") return 2 fightmap.outp.outp("You missed!") fightmap.show() fightmap.pball.remove() - enem.ico.add(fightmap, enem.ico.x, enem.ico.y) + enem.curr.ico.add(fightmap, enem.curr.ico.x, enem.curr.ico.y) fightmap.show() logging.info("[Fighitem][%s] Missed", name) return None - def potion(self, obj, enem, info, hp, name): + def potion(self, obj, enem, hp, name): """Potion function ARGS: obj: The players Poke object enem: The enemys Poke object - info: The info dict hp: The hp that will be given to the Poke name: The potions name""" - self.fig.remove_item(name) - obj.oldhp = obj.hp - if obj.hp + hp > obj.full_hp: - obj.hp = obj.full_hp - else: - obj.hp += hp - obj.hp_bar.update(obj.oldhp) + obj.remove_item(name) + obj.curr.oldhp = obj.curr.hp + obj.curr.hp = min(obj.curr.full_hp, obj.curr.hp + hp) + obj.curr.hp_bar.update(obj.curr.oldhp) logging.info("[Fighitem][%s] Used", name) - def heal_potion(self, obj, enem, info): + def heal_potion(self, obj, enem): """Healing potion function""" - return self.potion(obj, enem, info, 5, "healing_potion") + return self.potion(obj, enem, 5, "healing_potion") - def super_potion(self, obj, enem, info): + def super_potion(self, obj, enem): """Super potion function""" - return self.potion(obj, enem, info, 15, "super_potion") + return self.potion(obj, enem, 15, "super_potion") - def poketeball(self, obj, enem, info): + def poketeball(self, obj, enem): """Poketeball function""" - return self.throw(obj, enem, info, 1, "poketeball") + return self.throw(obj, enem, 1, "poketeball") - def superball(self, obj, enem, info): + def superball(self, obj, enem): """Superball function""" - return self.throw(obj, enem, info, 6, "superball") + return self.throw(obj, enem, 6, "superball") - def hyperball(self, obj, enem, info): + def hyperball(self, obj, enem): """Hyperball function""" - return self.throw(obj, enem, info, 1000, "hyperball") + return self.throw(obj, enem, 1000, "hyperball") - def ap_potion(self, obj, enem, info): + def ap_potion(self, obj, enem): """AP potion function""" - self.fig.remove_item("ap_potion") - for atc in obj.attack_obs: + obj.remove_item("ap_potion") + for atc in obj.curr.attack_obs: atc.set_ap(atc.max_ap) logging.info("[Fighitem][ap_potion] Used") -class Fight: - """Wrapper for fightmap.fight - ARGS: - figure: The Figure object""" - def __init__(self, figure): - self.figure = figure - - def __call__(self, player, enemy, info=None): - """Wrapper for fightmap.fight - ARGS: - player: The players Poke - enemy: The enemys Poke - info: Dict containing info about the fight""" - if info is None: - info = {"type": "wild", "player": " "} - return fightmap.fight(player, enemy, self.figure, info) - - -fight = None -fightitems = None +fightitems = FightItems() fightmap = None diff --git a/pokete_classes/landscape.py b/pokete_classes/landscape.py index 00eda6da..54ee810a 100644 --- a/pokete_classes/landscape.py +++ b/pokete_classes/landscape.py @@ -4,6 +4,7 @@ import scrap_engine as se import pokete_data as p_data from pokete_classes import timer, movemap as mvp, fightmap as fm +from .providers import NatureProvider from .color import Color from .general import check_walk_back from .poke import Poke @@ -26,18 +27,26 @@ def action(self, ob): or (not n_a and not is_night) or (n_a and is_night)} if random.randint(0, 8) == 0: - fm.fight(Poke("__fallback__", 0) - if len([poke for poke in self.figure.pokes[:6] - if poke.hp > 0]) == 0 - else - [poke for poke in self.figure.pokes[:6] if poke.hp > 0][0], - Poke(random.choices(list(pokes), - weights=[i["rarity"] for _, i in - pokes.items()])[0], - random.choices(list(range(self.arg_proto["minlvl"], - self.arg_proto["maxlvl"])))[ - 0], - player=False, shiny=(random.randint(0, 500) == 0))) + fm.fightmap.fight( + [ + self.figure, + NatureProvider( + Poke( + random.choices( + list(pokes), + weights=[i["rarity"] for i in pokes.values()] + )[0], + random.choice( + range( + self.arg_proto["minlvl"], + self.arg_proto["maxlvl"] + ) + ), + player=False, shiny=(random.randint(0, 500) == 0) + ) + ) + ] + ) check_walk_back(self.figure) diff --git a/pokete_classes/npcs.py b/pokete_classes/npcs.py index c360a01a..e1e022e9 100644 --- a/pokete_classes/npcs.py +++ b/pokete_classes/npcs.py @@ -2,9 +2,11 @@ import time import logging +import random import scrap_engine as se import pokete_classes.fightmap as fm import pokete_classes.movemap as mvp +from .providers import Provider from .loops import std_loop from .input import ask_bool from .inv_items import invitems @@ -194,18 +196,31 @@ def chat(self): q_a = q_a["a"][key] -class Trainer(NPC): +class Trainer(NPC, Provider): """Trainer class to fight against""" - def __init__(self, poke, name, gender, texts, lose_texts, + def __init__(self, pokes, name, gender, texts, lose_texts, win_texts): - super().__init__(name, texts, side_trigger=False) + NPC.__init__(self, name, texts, side_trigger=False) + Provider.__init__(self, pokes) # attributes self.gender = gender - self.poke = poke self.lose_texts = lose_texts self.win_texts = win_texts + def get_attack(self, fightmap, enem): + return random.choices( + self.curr.attack_obs, + weights=[ + i.ap * ( + 1.5 if enem.curr.type.name in i.type.effective + else 0.5 if enem.curr.type.name in i.type.ineffective + else 1 + ) + for i in self.curr.attack_obs + ] + )[0] + def add(self, _map, x, y): """Add wrapper See se.Box.add""" @@ -223,7 +238,8 @@ def action(self): o_y = self.y if self.fig.has_item("shut_the_fuck_up_stone"): return - if self.poke.hp > 0 and (not self.used + self.pokes = [p for p in self.pokes if p.hp > 0] + if self.pokes and (not self.used or not settings("save_trainers").val) \ and self.check_walk(self.fig.x, self.fig.y): mvp.movemap.full_show() @@ -232,17 +248,17 @@ def action(self): self.walk_point(self.fig.x, self.fig.y) if any(poke.hp > 0 for poke in self.fig.pokes[:6]): self.text(self.texts) - winner = fm.fight([poke for poke in self.fig.pokes[:6] - if poke.hp > 0][0], - self.poke, - info={"type": "duel", "player": self}) + winner = fm.fightmap.fight( + [self.fig, self] + ) + is_winner = (winner == self) self.text({True: self.lose_texts, False: self.win_texts + [" < Here's $20!"]} - [winner == self.poke]) - if winner != self.poke: + [is_winner]) + if not is_winner: self.fig.add_money(20) self.set_used() logging.info("[NPC][%s] %s against player", self.name, - 'Lost' if winner != self.poke else 'Won') + 'Lost' if not is_winner else 'Won') self.walk_point(o_x, o_y + (1 if o_y > self.y else -1)) check_walk_back(self.fig) diff --git a/pokete_classes/poke.py b/pokete_classes/poke.py index 3ede2b51..69d46b1b 100644 --- a/pokete_classes/poke.py +++ b/pokete_classes/poke.py @@ -163,7 +163,7 @@ def lvl(self): Current level""" return int(math.sqrt(self.xp + 1)) - def attack(self, attack, enem, fightmap): + def attack(self, attack, enem, fightmap, weather): """Attack process ARGS: attack: Attack object @@ -179,7 +179,6 @@ def attack(self, attack, enem, fightmap): self.enem = enem = self else: self.enem = enem - weather = fightmap.figure.map.weather w_eff = 1 random_factor = random.choices([0, 0.75, 1, 1.26], weights=[attack.miss_chance diff --git a/pokete_classes/providers.py b/pokete_classes/providers.py new file mode 100644 index 00000000..ee87c4a5 --- /dev/null +++ b/pokete_classes/providers.py @@ -0,0 +1,54 @@ +import random + +class Provider: + """Provider can hold and manage Poketes + ARGS: + pokes: The Poketes the Provider holds""" + + def __init__(self, pokes): + self.pokes = pokes + self.play_index = 0 + + @property + def curr(self): + """Returns the currently used Pokete""" + return self.pokes[self.play_index] + + def index_conf(self): + """Sets index correctly""" + self.play_index = next( + i for i, poke in enumerate(self.pokes) if poke.hp > 0 + ) + + def get_attack(self, fightmap, enem): + """Returns the choosen attack: + ARGS: + fightmap: fightmap object + anem: The enemy Provider""" + raise NotImplementedError + +class NatureProvider(Provider): + """The Natures Provider + ARGS: + poke: One Pokete""" + def __init__(self, poke): + super().__init__([poke]) + + def get_attack(self, fightmap, enem): + """Returns the choosen attack: + ARGS: + fightmap: fightmap object + anem: The enemy Provider""" + return random.choices( + self.curr.attack_obs, + weights=[ + i.ap for i in self.curr.attack_obs + ] + )[0] + + +class ProtoFigure(Provider): + """Class Figure inherits from to avoid injecting the Figure class + into fight""" + pass + diff --git a/pokete_data/__init__.py b/pokete_data/__init__.py index 47dfdb88..02c68e2e 100644 --- a/pokete_data/__init__.py +++ b/pokete_data/__init__.py @@ -90,7 +90,7 @@ def validate(): "gen": ["additionals", "width", "height", "desc"], "add": ["x", "y"], "poke_ico": ["txt", "esc"], - "trainer": ["poke", "args"] + "trainer": ["pokes", "args"] } diff --git a/pokete_data/attacks.py b/pokete_data/attacks.py index 1e099247..b278cd31 100644 --- a/pokete_data/attacks.py +++ b/pokete_data/attacks.py @@ -389,7 +389,7 @@ "action": None, "world_action": "", "move": ["attack"], - "miss_chance": 0, + "miss_chance": 0.3, "min_lvl": 15, "desc": "Hans! Get ze Flammenwerfer!", "types": ["fire"], @@ -646,7 +646,7 @@ "action": None, "world_action": "", "move": ["downgrade"], - "miss_chance": 0, + "miss_chance": 0.2, "min_lvl": 0, "desc": "Causes confusion deep in the enemy's mind.", "types": ["undead"], @@ -689,7 +689,7 @@ "action": None, "world_action": "", "move": ["arch"], - "miss_chance": 0, + "miss_chance": 0.2, "min_lvl": 15, "desc": "Gives the enemy a massive shock.", "types": ["electro"], @@ -704,7 +704,7 @@ "action": None, "world_action": "", "move": ["downgrade"], - "miss_chance": 0, + "miss_chance": 0.1, "min_lvl": 0, "desc": "Spreads a special smell that will make the enemy confused but very happy.", "types": ["plant"], diff --git a/pokete_data/trainers.py b/pokete_data/trainers.py index 5a573733..4043fa1d 100644 --- a/pokete_data/trainers.py +++ b/pokete_data/trainers.py @@ -1,13 +1,13 @@ trainers = { "playmap_1": [{ - "poke": ("poundi", 60), + "pokes": [("poundi", 60)], "args": ("Franz", "He", [" < Wanna fight?"], [" < Hahaha!", " < You're a loser!"], [" < You're a very good trainer!"], 30, 10) }, ], "cave_1": [{ - "poke": ("hornita", 128), + "pokes": [("hornita", 128)], "args": ("Monica", "She", [" < Hello, noble traveler", " < Are you willing to fight me?"], [" < Hahaha!", " < Looooser!"], @@ -15,7 +15,7 @@ }, ], "playmap_2": [{ - "poke": ("ostri", 160), + "pokes": [("ostri", 160)], "args": ("Wanderer Murrad", "He", [" < Isn't it a great day?", " < I traveled here from a distant country", " < Do you want to fight against my rare Pokete?"], @@ -24,7 +24,7 @@ }, ], "playmap_3": [{ - "poke": ("hornita", 200), + "pokes": [("hornita", 200)], "args": ("Markus", "He", [" < Hey!", " < Welcome to Sunnydale!", " < But first, we must fight!"], [" < Hahaha!", " < Hahaha!", " < You're a loser!"], @@ -32,7 +32,7 @@ }, ], "playmap_4": [{ - "poke": ("karpi", 340), + "pokes": [("karpi", 340)], "args": ("Kevin", "He", [" < Yo!", " < Whaddup?", " < Wanna see my sick-ass Pokete?"], [" < Yeaaah!", " < My Pokete is sooo sick!"], @@ -40,7 +40,7 @@ }, ], "playmap_5": [{ - "poke": ("bator", 350), + "pokes": [("bator", 350)], "args": ("Caveman Marc", "He", [" < Oh!", " < I haven't seen anyone down here for a while", " < Can I show you my rare Pokete which can only be found in this cave?"], @@ -49,15 +49,15 @@ }, ], "playmap_6": [{ - "poke": ("treenator", 400), + "pokes": [("treenator", 400)], "args": ("Eva", "She", - [" < Hi!", " < Fight?"], + [" < Hi!", " < Fight?"], [" < Loser"], [" < I lost!"], 47, 43) }, ], "playmap_7": [{ - "poke": ("steini", 400), + "pokes": [("steini", 400)], "args": ("Caveman Dieter", "He", [" < Oh!", " < I didn't see you coming"], [" < My Steini is old but classy"], @@ -65,7 +65,7 @@ }, ], "playmap_8": [{ - "poke": ("gobost", 400), + "pokes": [("gobost", 400)], "args": ("Woodsman Bert", "He", [" < Do you see this abandoned house?", " < I caught this Pokete in there!"], [" < It's pretty cool huh?!"], @@ -73,7 +73,7 @@ }, ], "playmap_11": [{ - "poke": ("clampi", 450), + "pokes": [("clampi", 450)], "args": ("Fisherman's Friend", "He", [" < G'day, young trainer", " < I've lived here for years"], [" < Those years of training were worth it"], @@ -81,13 +81,13 @@ }, ], "playmap_12": [{ - "poke": ("blub", 600), + "pokes": [("blub", 600)], "args": ("Brother Justin", "He", [" < Hey, my brother and I want to fight!"], [" < Haha, you're bad!"], [" < Damn!"], 26, 10) }, { - "poke": ("poundi", 600), + "pokes": [("poundi", 600)], "args": ("Brother Justus", "He", [" < Now it's my turn!"], [" < Haha, you're bad!"], @@ -95,7 +95,7 @@ }, ], "playmap_13": [{ - "poke": ("vogli", 600), + "pokes": [("vogli", 600)], "args": ("Citizen", "He", [" < Hello, fellow stranger!", " < This town is known for its bird Poketes"], [" < Haha, you're bad!"], @@ -103,26 +103,26 @@ }, ], "playmap_14": [{ - "poke": ("owol", 650), + "pokes": [("owol", 650)], "args": ("First Trainer", "He", [" < Welcome to the Deepest Forest Pokete Arena", " < I'm your first enemy!"], [" < Haha, you're bad!"], [" < Good luck!"], 17, 10) }, { - "poke": ("voglo", 700), + "pokes": [("voglo", 700)], "args": ("Second Trainer", "She", [" < Now it's my turn!"], [" < Haha, you're bad!"], [" < Good luck with the next trainer!"], 22, 10) }, { - "poke": ("treenator", 750), + "pokes": [("treenator", 750)], "args": ("Third Trainer", "She", [" < Let's see what other Poketes you have!"], [" < Haha, you're bad!"], [" < Good luck with the last trainer!"], 22, 5) }, { - "poke": ("ostri", 780), + "pokes": [("ostri", 780)], "args": ("Last Trainer", "He", [" < I'm your last enemy!"], [" < Haha, you're bad!"], @@ -130,13 +130,13 @@ }, ], "playmap_15": [{ - "poke": ("clampi", 650), + "pokes": [("clampi", 650)], "args": ("Samantha", "She", [" < Hey, you!", " < My Pokete is very effective against bird Poketes"], [" < You see, it's effective"], [" < Oh no", " < I guess yours is even more effective than mine!"], 43, 17) }, { - "poke": ("angrilo", 650), + "pokes": [("angrilo", 650)], "args": ("Jessica", "She", [" < Hey you!"], [" < Haha, you're a loser!"], @@ -144,13 +144,13 @@ }, ], "playmap_18": [{ - "poke": ("poundi", 700), + "pokes": [("poundi", 700)], "args": ("Bert", "He", [" < Hey!", " < This region is full of stone and ground Poketes"], [" < Haha, you're bad!"], [" < Oh, I lost!"], 6, 4) }, { - "poke": ("clampi", 700), + "pokes": [("clampi", 700)], "args": ("Karen", "She", [" < I don't think you can walk here", " < I demand a fight with you!"], [" < Go home, little zoomer."], @@ -158,13 +158,13 @@ }, ], "playmap_19": [{ - "poke": ("choka", 850), + "pokes": [("choka", 850)], "args": ("Brian", "He", [" < Hello fellow cave diver!"], [" < Oooooh!", " < You're a loooser!"], [" < Oh!", " < You were lucky!"], 16, 15) }, { - "poke": ("wolfiro", 850), + "pokes": [("wolfiro", 850)], "args": ("Simon", "He", [" < Yoooo!", " < What's up?"], [" < You're a loooser!"], @@ -172,7 +172,7 @@ }, ], "playmap_21": [{ - "poke": ("bigstone", 900), + "pokes": [("bigstone", 900)], "args": ("Rock-hard Rick", "He", [" < Hello trainer!", " < Welcome to Rock-ville, the highest place in the Pokete world and home of all stone Poketes.", @@ -184,26 +184,26 @@ }, ], "playmap_27": [{ - "poke": ("bigstone", 900), + "pokes": [("bigstone", 900)], "args": ("Bertold", "He", [" < We are the elite of Rock-ville!"], [" < You're a loooser!"], [" < You were lucky!"], 6, 6) }, { - "poke": ("steini", 900), + "pokes": [("steini", 900)], "args": ("Gerard", "He", [" < My Steini will rip out your Pokete's heart!"], [" < You're a loooser!"], [" < The other trainers wont be as easy!"], 11, 10) }, { - "poke": ("treenator", 950), + "pokes": [("treenator", 950), ("lilstone", 950)], "args": ("Jessica", "She", [" < You wont be ready for my Treenator!"], [" < You're a loooser!"], [" < Our best trainer will defeat you though!"], 16, 6) }, { - "poke": ("poundi", 1000), + "pokes": [("poundi", 1000), ("steini", 1000), ("diamondos", 1000)], "args": ("First Trainer", "He", [" < Let's have a fair fight!"], [" < You're a loooser!"], @@ -211,26 +211,26 @@ }, ], "playmap_28": [{ - "poke": ("electrode", 950), + "pokes": [("electrode", 950)], "args": ("Steven the Big", "He", [" < I don't think you ever met an Electrode!"], [" < You're a loooser!"], [" < Hmph!", " < It's not as great as I thought!"], 36, 47) }, { - "poke": ("steini", 850), + "pokes": [("steini", 850)], "args": ("Laurena", "She", [" < I trained my Steini for years to get to this level", " > I will win!"], [" < You're a loooser!"], [" < Ohhh nooo!", " < NOT MY STEINI!!!1!!1"], 114, 37) }, { - "poke": ("poisopla", 950), + "pokes": [("poisopla", 950)], "args": ("Laurin", "They", [" < Poisopla is one of the strongest local Poketes!", " < And it will kill your lame Pokete!"], [" < You're a loooser!"], [" < It won't be as easy in 'Flowy Town'!"], 141, 23) }, { - "poke": ("confuso", 900), + "pokes": [("confuso", 900)], "args": ("Fucking badass looking dude in the woods", "He", [" < You have to beat my Pokete to enter 'Flowy Town'", " < I guess it'll confuse you!"], [" < You're a loooser!"], @@ -238,7 +238,7 @@ }, ], "playmap_30": [{ - "poke": ("poisopla", 950), + "pokes": [("poisopla", 950)], "args": ("Guy at the Entrance", "He", [" < Welcome to 'Flowy Town', home of the flowers."], [" < You're a loooser!"], @@ -246,26 +246,26 @@ }, ], "playmap_31": [{ - "poke": ("diamondos", 1000), + "pokes": [("diamondos", 1000)], "args": ("Luther", "He", [" < Welcome to the 'Flowy Town' Arena!"], [" < You're a loooser!"], [" < You were lucky!"], 22, 10) }, { - "poke": ("poisopla", 1000), + "pokes": [("poisopla", 1000)], "args": ("Heavy Hans", "He", [" < I don't think your Pokete is better than mine!"], [" < Your journey came to a fast end!"], [" < The other trainers wont be as easy!"], 25, 8) }, { - "poke": ("treenator", 1000), + "pokes": [("treenator", 1000)], "args": ("Aurelia", "She", [" < You wont be ready for my Treenator!"], [" < You're a loooser!"], [" < Our best trainer will defeat you though!"], 28, 6) }, { - "poke": ("rosi", 1200), + "pokes": [("rosi", 1200)], "args": ("Master of the Flowers", "He", [" < I'm the Master of the plants and I have one of the rarest plant Poketes!"], [" < You're a loooser!"], @@ -273,7 +273,7 @@ }, ], "playmap_33": [{ - "poke": ("mowcow", 1200), + "pokes": [("mowcow", 1200)], "args": ("Cowsay", "They", [" < This apt has supercow-powers!"], [" < You're a loooser!"], @@ -281,7 +281,7 @@ }, ], "playmap_35": [{ - "poke": ("mowcow", 1200), + "pokes": [("mowcow", 1200)], "args": ("Farmer Gert", "He", [" < Welcome to the fields of Agrawos!", " < This is the farming part of the city of Agrawos!", @@ -289,13 +289,13 @@ [" < I don't think you'll ever get there!"], [" < Have fun in Agrawos!"], 6, 17) }, { - "poke": ("dicki", 1250), + "pokes": [("dicki", 1250)], "args": ("Farmer Doora", "She", [" < This is a cool Pokete I found on my field!"], [" < It's cool, innit?!"], [" < I guess have still have to train it. :("], 74, 33) }, { - "poke": ("wolfiro", 1300), + "pokes": [("wolfiro", 1300)], "args": ("Farmer Ralf", "He", [" < DIE!"], [" < HAHAHA, IM BETTER THAN YOU!"], @@ -303,7 +303,7 @@ }, ], "playmap_39": [{ - "poke": ("megapois", 2000), + "pokes": [("megapois", 2000)], "args": ("Gardener Angela", "She", [" < Have you already fought our lead trainer?", " < If so, look at this cool Pokete!"], @@ -312,7 +312,7 @@ }, ], "playmap_40": [{ - "poke": ("rustacean", 1800), + "pokes": [("rustacean", 1800)], "args": ("Angler Gustav", "He", [" < My Pokete will blow you away!"], [" < You're a loooser!"], @@ -320,7 +320,7 @@ }, ], "playmap_41": [{ - "poke": ("wheeto", 2000), + "pokes": [("wheeto", 2000)], "args": ("Farmer Daniel", "He", [" < Howdy, partner!", " < How ya doin?", " < My Pokete is one of a kind", @@ -331,28 +331,28 @@ ], "playmap_46": [ { - "poke": ("wheeto", 2000), + "pokes": [("wheeto", 2000)], "args": ("Farmer Martin", "He", [" < Howdy, partner!", " < I will be your first challenger!"], [" < You'll do better next time."], [" < I wish you the best of luck"], 19, 7) }, { - "poke": ("dicko", 2100), + "pokes": [("dicko", 2100)], "args": ("The Undetermined", "They", [" < I see you're not as bad as we thought!"], [" < You'll do better next time."], [" < I wish you the best of luck"], 16, 7) }, { - "poke": ("megapois", 2200), + "pokes": [("megapois", 2200), ("bushy", 2200)], "args": ("Gardener Daniela", "She", [" < Look at my newest creation!"], [" < You'll do better next time."], [" < I wish you the best of luck"], 13, 7) }, { - "poke": ("mowcow", 2300), + "pokes": [("mowcow", 2300), ("treenator", 2300), ("wheeto", 2300)], "args": ("Leader Sebastian", "He", [" < So, I'll be your last opponent.", " < Let's have a fair fight!"],