Python宝可梦对战游戏中Base Power(基础威力)实现问题求助
Hey there! Let's fix up your Pokémon battle game to get those Base Powers working properly, along with move-specific effects like Eruption's variable power and Leaf Storm's attack drop. Here's a step-by-step solution with modified code:
Key Issues to Fix
First, let's address the core problems:
- Your moves are stored as strings, making it impossible to extract Base Power values programmatically
- The attribute logic was permanently altering Pokémon stats instead of using a multiplier for damage calculations
- Missing handling for move-specific effects (attack drops, variable power, healing)
- Incomplete damage formula that didn't account for Base Power or stat stages
Modified Full Code
import time import numpy as np import sys import random # Delay printing def delay_print(s): for c in s: sys.stdout.write(c) sys.stdout.flush() time.sleep(0.05) def calculate_base_power(attacker, move): """Calculate adjusted Base Power based on move-specific rules""" if move['name'] == 'Eruption': # Eruption's power scales with remaining HP (max 150, min 1) power_ratio = attacker.bars / attacker.max_bars adjusted_power = int(power_ratio * move['base_power']) return max(adjusted_power, 1) else: return move['base_power'] def calculate_damage(attacker, defender, move, type_multiplier): """Calculate damage using official Pokémon damage formula""" level = int(3 * (1 + np.mean([attacker.attack, defender.defense]))) # Handle stat stage multipliers (range: -6 to +6) attack_multiplier = (2 + attacker.attack_stage) / 2 if attacker.attack_stage >= 0 else 2 / (2 - attacker.attack_stage) defense_multiplier = (2 + defender.defense_stage) / 2 if defender.defense_stage >= 0 else 2 / (2 - defender.defense_stage) # Core damage formula damage = ((2 * level + 10) / 250) * \ (attacker.attack * attack_multiplier / (defender.defense * defense_multiplier)) * \ calculate_base_power(attacker, move) * \ type_multiplier + 2 return int(damage) # Create the class class Pokemon: def __init__(self, name, types, moves, EVs, health='==================='): self.name = name self.types = types self.moves = moves self.attack = EVs['ATTACK'] self.defense = EVs['DEFENSE'] self.health = health self.bars = 20 # Current HP bars self.max_bars = 20 # Max HP bars (for Eruption calculation) self.attack_stage = 0 # Attack stat stage (-6 to +6) self.defense_stage = 0 # Defense stat stage (-6 to +6) def fight(self, Pokemon2): print("POKEMON BATTLE WOOOOOOOOOOOO!!!!!!") print(f"\n{self.name}") print("TYPE/", self.types) print("ATTACK/", self.attack) print("DEFENSE/", self.defense) print("LVL/", 3 * (1 + np.mean([self.attack, self.defense]))) print("\nVS") print(f"\n{Pokemon2.name}") print("TYPE/", Pokemon2.types) print("ATTACK/", Pokemon2.attack) print("DEFENSE/", Pokemon2.defense) print("LVL/", 3 * (1 + np.mean([Pokemon2.attack, Pokemon2.defense]))) time.sleep(2) # Type advantage mapping (attacker type -> defender type -> multiplier) type_chart = { 'Fire': {'Fire': 0.5, 'Water': 0.5, 'Grass': 2}, 'Water': {'Fire': 2, 'Water': 0.5, 'Grass': 0.5}, 'Grass': {'Fire': 0.5, 'Water': 2, 'Grass': 0.5} } # Calculate multipliers for both sides self_type_multiplier = type_chart[self.types][Pokemon2.types] opponent_type_multiplier = type_chart[Pokemon2.types][self.types] # Set effectiveness messages def get_effectiveness_string(multiplier): if multiplier == 2: return '\nIts super effective!' elif multiplier == 0.5: return '\nIts not very effective...' else: return '' string_1_attack = get_effectiveness_string(self_type_multiplier) string_2_attack = get_effectiveness_string(opponent_type_multiplier) # Fight loop while (self.bars > 0) and (Pokemon2.bars > 0): # Print current health print(f"\n{self.name}\t\tHLTH\t{self.health}") print(f"{Pokemon2.name}\t\tHLTH\t{Pokemon2.health}\n") # Player 1 turn print(f"{self.name}, I choose you!") for i, move in enumerate(self.moves): print(f"{i + 1}. {move['name']}: {move['base_power']} Base Power, {move['effect']}") index = int(input('Pick a move: ')) - 1 selected_move = self.moves[index] delay_print(f"\n{self.name} used {selected_move['name']}!") time.sleep(1) delay_print(string_1_attack) time.sleep(1) # Calculate and apply damage damage_dealt = calculate_damage(self, Pokemon2, selected_move, self_type_multiplier) Pokemon2.bars -= damage_dealt Pokemon2.bars = max(Pokemon2.bars, 0) # Update health bar Pokemon2.health = "=" * int(Pokemon2.bars + 0.1 * Pokemon2.defense) # Handle move effects if selected_move['effect'] == 'lowers attack by 2 stages': self.attack_stage -= 2 self.attack_stage = max(min(self.attack_stage, 6), -6) delay_print(f"\n{self.name}'s attack fell sharply!") elif selected_move['effect'] == 'heal 50% of damage dealt': heal_amount = int(damage_dealt * 0.5) self.bars += heal_amount self.bars = min(self.bars, self.max_bars) self.health = "=" * int(self.bars + 0.1 * self.defense) delay_print(f"\n{self.name} healed {heal_amount} HP!") elif '10% chance to burn' in selected_move['effect']: if random.randint(1,10) == 1: # Add burn logic here if you want to implement status effects later delay_print(f"\n{Pokemon2.name} was burned!") time.sleep(1) print(f"\n{self.name}\t\tHLTH\t{self.health}") print(f"{Pokemon2.name}\t\tHLTH\t{Pokemon2.health}\n") time.sleep(.5) # Check if opponent fainted if Pokemon2.bars <= 0: delay_print("\n..." + Pokemon2.name + ' fainted. ' + self.name + " won!") break # Player 2 turn print(f"Let's go, {Pokemon2.name}!") for i, move in enumerate(Pokemon2.moves): print(f"{i + 1}. {move['name']}: {move['base_power']} Base Power, {move['effect']}") index = int(input('Pick a move: ')) - 1 selected_move = Pokemon2.moves[index] delay_print(f"\n{Pokemon2.name} used {selected_move['name']}!") time.sleep(1) delay_print(string_2_attack) time.sleep(1) # Calculate and apply damage damage_dealt = calculate_damage(Pokemon2, self, selected_move, opponent_type_multiplier) self.bars -= damage_dealt self.bars = max(self.bars, 0) # Update health bar self.health = "=" * int(self.bars + 0.1 * self.defense) # Handle move effects if selected_move['effect'] == 'lowers attack by 2 stages': Pokemon2.attack_stage -= 2 Pokemon2.attack_stage = max(min(Pokemon2.attack_stage, 6), -6) delay_print(f"\n{Pokemon2.name}'s attack fell sharply!") elif selected_move['effect'] == 'heal 50% of damage dealt': heal_amount = int(damage_dealt * 0.5) Pokemon2.bars += heal_amount Pokemon2.bars = min(Pokemon2.bars, Pokemon2.max_bars) Pokemon2.health = "=" * int(Pokemon2.bars + 0.1 * Pokemon2.defense) delay_print(f"\n{Pokemon2.name} healed {heal_amount} HP!") elif '10% chance to burn' in selected_move['effect']: if random.randint(1,10) == 1: delay_print(f"\n{self.name} was burned!") time.sleep(1) print(f"{self.name}\t\tHLTH\t{self.health}") print(f"{Pokemon2.name}\t\tHLTH\t{Pokemon2.health}\n") time.sleep(.5) # Check if player fainted if self.bars <= 0: delay_print("\n..." + self.name + ' fainted. ' + Pokemon2.name + " won!") break if __name__ == '__main__': # Create Pokemon with structured move data Typhlosion = Pokemon( 'Typhlosion', 'Fire', [ {'name': 'Eruption', 'base_power': 150, 'effect': 'power decreases as health decreases'}, {'name': 'Fire Blast', 'base_power': 110, 'effect': '10% chance to burn'}, {'name': 'Flamethrower', 'base_power': 90, 'effect': '10% chance to burn'}, {'name': 'Overheat', 'base_power': 130, 'effect': 'lowers attack by 2 stages'} ], {'ATTACK': 12, 'DEFENSE': 8} ) Samurott = Pokemon( 'Samurott', 'Water', [ {'name': 'Razor Shell', 'base_power': 75, 'effect': 'no additional effect'}, {'name': 'Scald', 'base_power': 80, 'effect': '10% chance to burn'}, {'name': 'Hydro Pump', 'base_power': 120, 'effect': 'no additional effect'}, {'name': 'Surf', 'base_power': 90, 'effect': 'no additional effect'} ], {'ATTACK': 10, 'DEFENSE': 10} ) Serperior = Pokemon( 'Serperior', 'Grass', [ {'name': 'Leaf Storm', 'base_power': 130, 'effect': 'lowers attack by 2 stages'}, {'name': 'Energy Ball', 'base_power': 90, 'effect': 'no additional effect'}, {'name': 'Giga Drain', 'base_power': 75, 'effect': 'heal 50% of damage dealt'}, {'name': 'Solar Beam', 'base_power': 120, 'effect': 'takes two turns to charge (not implemented yet)'} ], {'ATTACK': 19, 'DEFENSE': 1} ) Typhlosion.fight(Samurott) # Start battle money = np.random.choice(5000) delay_print(f"\nOpponent paid you ${money}. Good luck in the future and win more battles!\n")
What Changed & Why
- Structured Move Data: Moves are now dictionaries storing
name,base_power, andeffect—this lets us easily access Base Power values and trigger effects programmatically. - Proper Base Power Calculation: The
calculate_base_powerfunction handles Eruption's variable power based on remaining HP. - Official Damage Formula: The
calculate_damagefunction follows the standard Pokémon damage formula, including stat stages, type multipliers, and Base Power. - Stat Stage Handling: Added
attack_stageanddefense_stageattributes to track temporary stat changes (like from Overheat/Leaf Storm). - Move Effect Logic: Implemented handling for attack drops, healing (Giga Drain), and burn chances.
- Fixed Attribute Advantage: Instead of permanently altering Pokémon stats, we use a multiplier in damage calculations (true to how Pokémon battles work).
内容的提问来源于stack exchange,提问作者Navzyx-kun




