Files
infinitefusion-e18/Data/Scripts/053_PIF_Hoenn/TrainerRematches/TrainerRematch_Trade.rb
T
2026-07-10 15:42:06 -04:00

245 lines
6.8 KiB
Ruby

# Higher values: pickier
TRAINER_CLASS_PICKINESS = {
# TIER 1: Masters (2.4-3.0)
CHAMPION_Steven: 3.0,
ELITEFOUR_Drake: 2.8,
ELITEFOUR_Glacia: 2.8,
ELITEFOUR_Phoebe: 2.8,
ELITEFOUR_Sidney: 2.8,
TEAM_AQUA_BOSS: 2.8,
TEAM_MAGMA_BOSS: 2.8,
LEADER_Wallace: 2.7,
LEADER_Juan: 2.7,
LEADER_Roxanne: 2.6,
LEADER_Brawly: 2.6,
LEADER_Wattson: 2.6,
LEADER_Flannery: 2.6,
LEADER_Norman: 2.6,
LEADER_Winona: 2.6,
LEADER_Tate: 2.6,
LEADER_Liza: 2.6,
PROFESSOR: 2.5,
EXPERT_M: 2.5,
EXPERT_F: 2.5,
# TIER 2: Professionals & wealthy (1.9 - 2.3)
COOLTRAINER_M: 2.3,
COOLTRAINER_F: 2.3,
COOLTRAINER_M2: 2.3,
COOLTRAINER_F2: 2.3,
DRAGONTAMER: 2.3,
LADY: 2.4,
GENTLEMAN: 2.3,
SOCIALITE: 2.3,
RICHBOY: 2.3,
COLLECTOR: 2.3,
BEAUTY: 2.2,
KIMONOGIRL: 2.2,
SAGE: 2.1,
COOLCOUPLE: 2.1,
ENGINEER: 2.0,
PAINTER: 2.0,
SCIENTIST: 2.0,
POKEMONRANGER_M: 2.0,
POKEMONRANGER_F: 2.0,
PSYCHIC_M: 2.0,
PSYCHIC_F: 2.0,
TEACHER: 2.0,
NURSE: 2.0,
POKEMONBREEDER_F: 1.9,
POKEMONBREEDER_M: 1.9,
SUPERNERD: 1.9,
# TIER 3: Hobbyists (1.5 - 1.8)
AROMALADY: 1.8,
JUGGLER: 1.8,
POLICE: 1.8,
PARASOLLADY: 1.8,
SECRETBASEEXPERT: 1.8,
CHANNELER: 1.7,
BLACKBELT: 1.7,
HAUNTEDGIRL: 1.7,
CRUSHKIN: 1.7,
POKEMANIAC: 1.6,
BUGMANIAC: 1.6,
POKEFAN_M: 1.6,
POKEFAN_F: 1.6,
CRUSHGIRL: 1.6,
YOUNGCOUPLE: 1.6,
YOUNGCOUPLE_M: 1.6,
YOUNGCOUPLE_F: 1.6,
WORKER: 1.6,
PYROMANIAC: 1.6,
SKIER_F: 1.6,
GAMBLER: 1.5,
HIKER: 1.5,
RUINMANIAC: 1.5,
TAMER: 1.5,
CLOWN: 1.5,
FARMER: 1.5,
REPORTER: 1.5,
CAMERAMAN: 1.5,
TRIATHLETE_BIKE_M: 1.5,
TRIATHLETE_BIKE_F: 1.5,
TRIATHLETE_SWIM_M: 1.5,
TRIATHLETE_SWIM_F: 1.5,
TRIATHLETE_RUN_M: 1.5,
TRIATHLETE_RUN_F: 1.5,
# TIER 4: Average joes (1.1 - 1.4)
BIRDKEEPER: 1.4,
FISHERMAN: 1.4,
ROCKER: 1.4,
ROUGHNECK: 1.4,
SCHOOLMATE_SR: 1.4,
BURGLAR: 1.3,
CUEBALL: 1.3,
SAILOR: 1.3,
SISANDBRO: 1.3,
DELIVERYMAN: 1.3,
HAUNTEDGIRL_YOUNG: 1.3,
SURFER: 1.3,
DIVER_M: 1.3,
DIVER_F: 1.3,
SWIMMER_M: 1.3,
SWIMMER_F: 1.3,
SWIMMER2_M: 1.3,
SWIMMER2_F: 1.3,
BIKER: 1.2,
CAMPER: 1.2,
PICNICKER: 1.2,
STREETTHUG: 1.2,
DELINQUENT: 1.2,
SCHOOLBOY: 1.2,
SCHOOLGIRL: 1.2,
NINJABOY: 1.2,
BUGCATCHER: 1.1,
BUGCATCHER_F: 1.1,
SCHOOLMATE_JR: 1.1,
# TIER 5: Novices & children
LASS: 1.0,
PLAYER: 1.0,
TWINS: 1.0,
TWIN_1: 1.0,
TWIN_2: 1.0,
YOUNGSTER: 0.9,
TUBER_M: 0.8,
TUBER_F: 0.8,
TUBER2_M: 0.8,
TUBER2_F: 0.8,
PRESCHOOLER_M: 0.6,
PRESCHOOLER_F: 0.6
}
def evaluate_pokemon_worth(pkmn, compare_level: nil, favorite_type: nil)
species_data = pkmn.species_data
return 0 unless species_data
level = pkmn.level
level_diff = compare_level ? (level - compare_level) : 0
level_score = level * 2 + [level_diff, 0].max * 1.5 # bonus if player's level is higher
base_stats_score = species_data.base_stats.values.sum / 10.0
rarity_score = (255 - species_data.catch_rate) / 5.0
iv_score = (pkmn.iv&.values&.sum || 0) / 4.0
shiny_score = pkmn.shiny? ? 50 : 0
fusion_bonus = pkmn.isFusion? ? 40 : 0
type_exists = GameData::Type.exists?(favorite_type) || nil
type_bonus = (type_exists && pkmn.hasType?(favorite_type)) ? 30 : 0
score = level_score +
base_stats_score +
rarity_score +
iv_score +
shiny_score +
fusion_bonus +
type_bonus
echoln("#{pkmn.name} - Score : #{score}")
return score
end
def offerPokemonForTrade(player_pokemon, npc_party, trainer_class, favorite_type)
player_score = evaluate_pokemon_worth(player_pokemon, favorite_type: favorite_type)
pickiness = TRAINER_CLASS_PICKINESS[trainer_class] || 1.0
# Evaluate all NPC Pokémon scores
npc_scores = npc_party.map do |npc_pkmn|
[npc_pkmn, evaluate_pokemon_worth(npc_pkmn, compare_level: player_pokemon.level, favorite_type: favorite_type)]
end
best_npc_pokemon, best_score = npc_scores.max_by { |_, score| score }
return best_npc_pokemon if player_score > best_score
max_difference = [player_score, 100].min * pickiness
candidates = npc_scores.select do |npc_pkmn, npc_score|
(npc_score - player_score).abs <= max_difference
end
return nil if candidates.empty?
candidates.min_by do |_, npc_score|
(npc_score - player_score).abs
end.first
end
def doNPCTrainerTrade(trainer)
echoln "Time since last trade: #{trainer.getTimeSinceLastTrade}"
unless trainer.isNextTradeReady?
pbMessage(_INTL("The trainer is not ready to trade yet. Wait a little bit before you make your offer."))
return trainer
end
return generateTrainerTradeOffer(trainer)
end
# prefered type depends on the trainer class
#
def generateTrainerTradeOffer(trainer)
wanted_types = BattledTrainer::TRAINER_CLASS_FAVORITE_TYPES[trainer.trainerType]
wanted_types = [:NORMAL] if !wanted_types || wanted_types.empty?
if wanted_types.include?(:ANY)
pbChoosePokemon(1, 2)
else
wanted_types_string = wanted_types.map { |type|
type_name = GameData::Type.get(type).real_name
"\\C[1]#{type_name}\\C[0]"
}.join(", ")
trainerClassName = GameData::TrainerType.get(trainer.trainerType).real_name
pbMessage(_INTL("{1} {2} is looking for Pokémon of the following type(s):\\n{3}\\nWhich Pokémon do you want to trade?",
trainerClassName, trainer.trainerName, wanted_types_string))
pbChoosePokemon(1, 2,
proc { |pokemon|
pokemon.hasOneOfTheseTypes?(wanted_types)
})
end
chosen_index = pbGet(1)
if chosen_index && chosen_index >= 0
chosen_pokemon = $Trainer.party[chosen_index]
offered_pokemon = offerPokemonForTrade(chosen_pokemon, trainer.currentTeam, trainer.trainerType, trainer.favorite_type)
if !offered_pokemon
pbMessage(_INTL("{1} {2} does not want to trade...", trainerClassName, trainer.trainerName))
return trainer
end
pif_sprite = BattleSpriteLoader.new.get_pif_sprite_from_species(offered_pokemon.species)
message = _INTL("{1} {2} is offering {3} (Level {4}) for your {5}.", trainerClassName, trainer.trainerName, offered_pokemon.name, offered_pokemon.level, chosen_pokemon.name)
showPokemonInPokeballWithMessage(pif_sprite, message)
if pbConfirmMessage(_INTL("Trade away {1} for {2} {3}'s {4}?", chosen_pokemon.name, trainerClassName, trainer.trainerName, offered_pokemon.name))
pbStartTrade(chosen_index, offered_pokemon, offered_pokemon.name, trainer.trainerName, 0)
updated_party = trainer.currentTeam
trainer.increase_friendship(10) if GameData::Type.exists?(trainer.favorite_type) && offered_pokemon.hasType?(trainer.favorite_type)
updated_party.delete(offered_pokemon)
updated_party << chosen_pokemon.clone
trainer.previous_trade_timestamp = Time.now
trainer.increase_friendship(20)
trainer.process_party_pokemon_held_items
return trainer
end
end
return trainer
trainer.set_pending_action(false) if trainer
return trainer
end