You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

  1. Structured Move Data: Moves are now dictionaries storing name, base_power, and effect—this lets us easily access Base Power values and trigger effects programmatically.
  2. Proper Base Power Calculation: The calculate_base_power function handles Eruption's variable power based on remaining HP.
  3. Official Damage Formula: The calculate_damage function follows the standard Pokémon damage formula, including stat stages, type multipliers, and Base Power.
  4. Stat Stage Handling: Added attack_stage and defense_stage attributes to track temporary stat changes (like from Overheat/Leaf Storm).
  5. Move Effect Logic: Implemented handling for attack drops, healing (Giga Drain), and burn chances.
  6. 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

火山引擎 最新活动