mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-12 23:44:58 +00:00
6.6 update
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
|
||||
#eventType
|
||||
# :EVOLVE
|
||||
# :FUSE
|
||||
# :UNFUSE
|
||||
# :REVERSE
|
||||
# :CAUGHT
|
||||
class BattledTrainerRandomEvent
|
||||
attr_accessor :eventType
|
||||
attr_accessor :caught_pokemon #species_sym
|
||||
|
||||
attr_accessor :unevolved_pokemon #species_sym
|
||||
attr_accessor :evolved_pokemon #species_sym
|
||||
|
||||
attr_accessor :fusion_head_pokemon #species_sym
|
||||
attr_accessor :fusion_body_pokemon #species_sym
|
||||
attr_accessor :fusion_fused_pokemon #species_sym
|
||||
|
||||
|
||||
attr_accessor :unreversed_pokemon #species_sym
|
||||
attr_accessor :reversed_pokemon #species_sym
|
||||
|
||||
|
||||
attr_accessor :unfused_pokemon #species_sym
|
||||
|
||||
|
||||
|
||||
def initialize(eventType)
|
||||
@eventType = eventType
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,217 @@
|
||||
class BattledTrainer
|
||||
DELAY_BETWEEN_NPC_TRADES = 180 #In seconds (3 minutes)
|
||||
MAX_FRIENDSHIP = 100
|
||||
|
||||
attr_accessor :trainerType
|
||||
attr_accessor :trainerName
|
||||
|
||||
attr_accessor :currentTeam #list of Pokemon. The game selects in this list for trade offers. They can increase levels & involve as you rebattle them.
|
||||
|
||||
#trainers will randomly find items and add them to this list. When they have the :ITEM status, they will
|
||||
# give one of them at random.
|
||||
#Items equipped to the Pokemon traded by the player will end up in that list.
|
||||
#
|
||||
# If there is an evolution that the trainer can use on one of their Pokemon in that list, they will
|
||||
# instead use it to evolve their Pokemon.
|
||||
#
|
||||
#DNA Splicers/reversers can be used on their Pokemon if they have at least 2 unfused/1 fused
|
||||
#
|
||||
#Healing items that are in that list can be used by the trainer in rematches
|
||||
#
|
||||
attr_accessor :foundItems
|
||||
|
||||
|
||||
attr_accessor :nb_rematches
|
||||
|
||||
#What the trainer currently wants to do
|
||||
# :IDLE -> Nothing. Normal postbattle dialogue
|
||||
# Should prompt the player to register the trainer in their phone.
|
||||
# Or maybe done automatically at the end of the battle?
|
||||
|
||||
# :TRADE -> Trainer wants to trade one of its Pokémon with the player
|
||||
|
||||
# :BATTLE -> Trainer wants to rebattle the player
|
||||
|
||||
# :ITEM -> Trainer has an item they want to give the player
|
||||
attr_accessor :current_status
|
||||
attr_accessor :previous_status
|
||||
attr_accessor :previous_trade_timestamp
|
||||
|
||||
attr_accessor :favorite_type
|
||||
attr_accessor :favorite_pokemon #Used for generating trade offers. Should be set from trainer.txt (todo)
|
||||
#If empty, then trade offers ask for a Pokemon of a type depending on the trainer's class
|
||||
|
||||
attr_accessor :previous_random_events
|
||||
attr_accessor :has_pending_action
|
||||
attr_accessor :custom_appearance
|
||||
|
||||
attr_accessor :friendship #increases the more you interact with them, unlocks more interact options
|
||||
attr_accessor :friendship_level
|
||||
def initialize(trainerType,trainerName,trainerVersion)
|
||||
@trainerType = trainerType
|
||||
@trainerName = trainerName
|
||||
@currentTeam = loadOriginalTrainerTeam(trainerVersion)
|
||||
@foundItems = []
|
||||
@nb_rematches = 0
|
||||
@currentStatus = :IDLE
|
||||
@previous_status = :IDLE
|
||||
@previous_trade_timestamp = Time.now-DELAY_BETWEEN_NPC_TRADES
|
||||
@previous_random_events =[]
|
||||
@has_pending_action=false
|
||||
@favorite_type = pick_favorite_type(trainerType)
|
||||
@friendship = 0
|
||||
@friendship_level = 0
|
||||
end
|
||||
|
||||
def friendship_level
|
||||
@friendship_level =0 if !@friendship_level
|
||||
return @friendship_level
|
||||
end
|
||||
def increase_friendship(amount)
|
||||
@friendship=0 if !@friendship
|
||||
@friendship_level=0 if !@friendship_level
|
||||
gain = amount / ((@friendship + 1) ** 0.4)
|
||||
@friendship += gain
|
||||
@friendship = MAX_FRIENDSHIP if @friendship > MAX_FRIENDSHIP
|
||||
|
||||
echoln "Friendship with #{@trainerName} increased by #{gain.round(2)} (total: #{@friendship.round(2)})"
|
||||
|
||||
thresholds = FRIENDSHIP_LEVELS[@trainerType] || []
|
||||
echoln thresholds
|
||||
|
||||
while @friendship_level < thresholds.length && @friendship >= thresholds[@friendship_level]
|
||||
@friendship_level += 1
|
||||
|
||||
trainerClassName = GameData::TrainerType.get(@trainerType).real_name
|
||||
pbMessage(_INTL("\\C[3]Friendship increased with #{trainerClassName} #{@trainerName}!"))
|
||||
case @friendship_level
|
||||
when 1
|
||||
pbMessage(_INTL("You can now trade with each other!"))
|
||||
when 2
|
||||
pbMessage(_INTL("They will now give you items from time to time!"))
|
||||
when 3
|
||||
pbMessage(_INTL("You can now partner up with them!"))
|
||||
end
|
||||
|
||||
echoln "🎉 #{@trainerName}'s friendship level increased to #{@friendship_level}!"
|
||||
end
|
||||
end
|
||||
|
||||
def set_custom_appearance(trainer_appearance)
|
||||
@custom_appearance = trainer_appearance
|
||||
end
|
||||
|
||||
def pick_favorite_type(trainer_type)
|
||||
if TRAINER_CLASS_FAVORITE_TYPES.has_key?(trainer_type)
|
||||
return TRAINER_CLASS_FAVORITE_TYPES[trainer_type].sample
|
||||
else
|
||||
return :NORMAL
|
||||
end
|
||||
end
|
||||
|
||||
def set_pending_action(value)
|
||||
@has_pending_action=value
|
||||
end
|
||||
|
||||
def log_evolution_event(unevolved_pokemon_species, evolved_pokemon_species)
|
||||
echoln "NPC Trainer #{@trainerName} evolved their #{get_species_readable_internal_name(unevolved_pokemon_species)} to #{get_species_readable_internal_name(evolved_pokemon_species)}!"
|
||||
|
||||
event = BattledTrainerRandomEvent.new(:EVOLVE)
|
||||
event.unevolved_pokemon = unevolved_pokemon_species
|
||||
event.evolved_pokemon = evolved_pokemon_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_fusion_event(body_pokemon_species, head_pokemon_species, fused_pokemon_species)
|
||||
echoln "NPC trainer #{@trainerName} fused #{body_pokemon_species} and #{head_pokemon_species}!"
|
||||
event = BattledTrainerRandomEvent.new(:FUSE)
|
||||
event.fusion_body_pokemon =body_pokemon_species
|
||||
event.fusion_head_pokemon =head_pokemon_species
|
||||
event.fusion_fused_pokemon =fused_pokemon_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_unfusion_event(original_fused_pokemon_species, unfused_body_species, unfused_body_head)
|
||||
echoln "NPC trainer #{@trainerName} unfused #{get_species_readable_internal_name(original_fused_pokemon_species)}!"
|
||||
event = BattledTrainerRandomEvent.new(:UNFUSE)
|
||||
event.unfused_pokemon = original_fused_pokemon_species
|
||||
event.fusion_body_pokemon = unfused_body_species
|
||||
event.fusion_head_pokemon = unfused_body_head
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_reverse_event(original_fused_pokemon_species, reversed_fusion_species)
|
||||
echoln "NPC trainer #{@trainerName} reversed #{get_species_readable_internal_name(original_fused_pokemon_species)}!"
|
||||
|
||||
event = BattledTrainerRandomEvent.new(:REVERSE)
|
||||
event.unreversed_pokemon = original_fused_pokemon_species
|
||||
event.reversed_pokemon = reversed_fusion_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_catch_event(new_pokemon_species)
|
||||
echoln "NPC Trainer #{@trainerName} caught a #{new_pokemon_species}!"
|
||||
event = BattledTrainerRandomEvent.new(:CATCH)
|
||||
event.caught_pokemon = new_pokemon_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def clear_previous_random_events()
|
||||
@previous_random_events = []
|
||||
end
|
||||
|
||||
def loadOriginalTrainer(trainerVersion=0)
|
||||
return pbLoadTrainer(@trainerType,@trainerName,trainerVersion)
|
||||
end
|
||||
|
||||
def loadOriginalTrainerTeam(trainerVersion=0)
|
||||
original_trainer = pbLoadTrainer(@trainerType,@trainerName,trainerVersion)
|
||||
return if !original_trainer
|
||||
echoln "Loading Trainer #{@trainerType}"
|
||||
current_party = []
|
||||
original_trainer.party.each do |partyMember|
|
||||
echoln "PartyMember: #{partyMember}"
|
||||
if partyMember.is_a?(Pokemon)
|
||||
current_party << partyMember
|
||||
elsif partyMember.is_a?(Array) #normally always gonna be this
|
||||
pokemon_species = partyMember[0]
|
||||
pokemon_level = partyMember[1]
|
||||
current_party << Pokemon.new(pokemon_species,pokemon_level)
|
||||
else
|
||||
echoln "Could not add Pokemon #{partyMember} to rematchable trainer's party."
|
||||
end
|
||||
end
|
||||
|
||||
return current_party
|
||||
end
|
||||
|
||||
def getTimeSinceLastTrade()
|
||||
@previous_trade_timestamp ||= Time.now - DELAY_BETWEEN_NPC_TRADES
|
||||
return Time.now - @previous_trade_timestamp
|
||||
end
|
||||
|
||||
def isNextTradeReady?()
|
||||
return getTimeSinceLastTrade < DELAY_BETWEEN_NPC_TRADES
|
||||
end
|
||||
|
||||
def list_team_unfused_pokemon
|
||||
list = []
|
||||
@currentTeam.each do |pokemon|
|
||||
list << pokemon if !pokemon.isFusion?
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
def list_team_fused_pokemon
|
||||
list = []
|
||||
@currentTeam.each do |pokemon|
|
||||
list << pokemon if pokemon.isFusion?
|
||||
end
|
||||
return list
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,70 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class PokemonGlobalMetadata
|
||||
#Map that keeps track of all the npc trainers the player has battled
|
||||
# [map_id,event_id] =>BattledTrainer
|
||||
attr_accessor :battledTrainers
|
||||
end
|
||||
|
||||
TIME_FOR_RANDOM_EVENTS = 60#3600 #1 hour
|
||||
|
||||
|
||||
## Extend pbTrainerBattle to call postTrainerBattleAction at the end of every trainer battle
|
||||
alias original_pbTrainerBattle pbTrainerBattle
|
||||
def pbTrainerBattle(trainerID, trainerName,endSpeech=nil,
|
||||
doubleBattle=false, trainerPartyID=0,
|
||||
*args)
|
||||
result = original_pbTrainerBattle(trainerID, trainerName, endSpeech,doubleBattle,trainerPartyID, *args)
|
||||
postTrainerBattleActions(trainerID, trainerName,trainerPartyID) if Settings::GAME_ID == :IF_HOENN
|
||||
return result
|
||||
end
|
||||
def postTrainerBattleActions(trainerID, trainerName,trainerVersion)
|
||||
trainer = registerBattledTrainer(@event_id,$game_map.map_id,trainerID,trainerName,trainerVersion)
|
||||
makeRebattledTrainerTeamGainExp(trainer)
|
||||
end
|
||||
|
||||
|
||||
#Do NOT call this alone. Rebattlable trainers are always intialized after
|
||||
# defeating them.
|
||||
# Having a rematchable trainer that is not registered will cause crashes.
|
||||
def registerBattledTrainer(event_id, mapId, trainerType, trainerName, trainerVersion=0)
|
||||
key = [event_id,mapId]
|
||||
$PokemonGlobal.battledTrainers = {} unless $PokemonGlobal.battledTrainers
|
||||
trainer = BattledTrainer.new(trainerType, trainerName, trainerVersion)
|
||||
$PokemonGlobal.battledTrainers[key] = trainer
|
||||
return trainer
|
||||
end
|
||||
|
||||
def unregisterBattledTrainer(event_id, mapId)
|
||||
key = [event_id,mapId]
|
||||
$PokemonGlobal.battledTrainers = {} unless $PokemonGlobal.battledTrainers
|
||||
if $PokemonGlobal.battledTrainers.has_key?(key)
|
||||
$PokemonGlobal.battledTrainers[key] =nil
|
||||
echoln "Unregistered Battled Trainer #{key}"
|
||||
else
|
||||
echoln "Could not unregister Battled Trainer #{key}"
|
||||
end
|
||||
end
|
||||
|
||||
def resetTrainerRebattle(event_id, map_id)
|
||||
trainer = getRebattledTrainer(event_id,map_id)
|
||||
|
||||
trainerType = trainer.trainerType
|
||||
trainerName = trainer.trainerName
|
||||
|
||||
unregisterBattledTrainer(event_id,map_id)
|
||||
registerBattledTrainer(event_id,map_id,trainerType,trainerName)
|
||||
end
|
||||
|
||||
def updateRebattledTrainer(event_id,map_id,updated_trainer)
|
||||
key = [event_id,map_id]
|
||||
$PokemonGlobal.battledTrainers = {} if !$PokemonGlobal.battledTrainers
|
||||
$PokemonGlobal.battledTrainers[key] = updated_trainer
|
||||
end
|
||||
|
||||
def getRebattledTrainer(event_id,map_id)
|
||||
key = [event_id,map_id]
|
||||
$PokemonGlobal.battledTrainers = {} if !$PokemonGlobal.battledTrainers
|
||||
return $PokemonGlobal.battledTrainers[key]
|
||||
end
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# After each rematch, all of the trainer's Pokémon gain EXP
|
||||
#
|
||||
# Gained Exp is calculated from the Pokemon that is in the first slot in the player's team
|
||||
# so the trainer's levels will scale with the player's.
|
||||
#
|
||||
# e.g. If the player uses a stronger Pokemon in the battle, the NPC will get more experience
|
||||
# as a result
|
||||
#
|
||||
def makeRebattledTrainerTeamGainExp(trainer, playerWon=true, gained_exp=nil)
|
||||
return if !trainer
|
||||
updated_team = []
|
||||
|
||||
trainer_pokemon = $Trainer.party[0]
|
||||
return if !trainer_pokemon
|
||||
for pokemon in trainer.currentTeam
|
||||
if !gained_exp #Set depending on first pokemon in party if not given a specific amount
|
||||
gained_exp = trainer_pokemon.level * trainer_pokemon.base_exp
|
||||
gained_exp /= 2 if playerWon #trainer lost so he's not getting full exp
|
||||
gained_exp /= trainer.currentTeam.length
|
||||
end
|
||||
growth_rate = pokemon.growth_rate
|
||||
new_exp = growth_rate.add_exp(pokemon.exp, gained_exp)
|
||||
pokemon.exp = new_exp
|
||||
updated_team.push(pokemon)
|
||||
end
|
||||
trainer.currentTeam = updated_team
|
||||
return trainer
|
||||
end
|
||||
|
||||
def evolveRebattledTrainerPokemon(trainer)
|
||||
updated_team = []
|
||||
for pokemon in trainer.currentTeam
|
||||
evolution_species = pokemon.check_evolution_on_level_up(false)
|
||||
if evolution_species
|
||||
trainer.log_evolution_event(pokemon.species,evolution_species)
|
||||
trainer.set_pending_action(true)
|
||||
pokemon.species = evolution_species if evolution_species
|
||||
end
|
||||
updated_team.push(pokemon)
|
||||
end
|
||||
trainer.currentTeam = updated_team
|
||||
return trainer
|
||||
end
|
||||
|
||||
def healRebattledTrainerPokemon(trainer)
|
||||
for pokemon in trainer.currentTeam
|
||||
pokemon.calc_stats
|
||||
pokemon.heal
|
||||
end
|
||||
return trainer
|
||||
end
|
||||
|
||||
def doNPCTrainerRematch(trainer)
|
||||
return generateTrainerRematch(trainer)
|
||||
end
|
||||
def generateTrainerRematch(trainer)
|
||||
trainer_data = GameData::Trainer.try_get(trainer.trainerType, trainer.trainerName, 0)
|
||||
|
||||
loseDialog = trainer_data&.loseText_rematch ? trainer_data.loseText_rematch : "..."
|
||||
if customTrainerBattle(trainer.trainerName,trainer.trainerType, trainer.currentTeam,nil,loseDialog)
|
||||
updated_trainer = makeRebattledTrainerTeamGainExp(trainer,true)
|
||||
updated_trainer = healRebattledTrainerPokemon(updated_trainer)
|
||||
else
|
||||
updated_trainer =makeRebattledTrainerTeamGainExp(trainer,false)
|
||||
end
|
||||
updated_trainer.set_pending_action(false)
|
||||
updated_trainer = evolveRebattledTrainerPokemon(updated_trainer)
|
||||
trainer.increase_friendship(5)
|
||||
return updated_trainer
|
||||
end
|
||||
|
||||
def showPrerematchDialog()
|
||||
event = pbMapInterpreter.get_character(0)
|
||||
map_id = $game_map.map_id if map_id.nil?
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
return "" if trainer.nil?
|
||||
|
||||
trainer_data = GameData::Trainer.try_get(trainer.trainerType, trainer.trainerName, 0)
|
||||
|
||||
all_previous_random_events = trainer.previous_random_events
|
||||
|
||||
if all_previous_random_events
|
||||
previous_random_event = getBestMatchingPreviousRandomEvent(trainer_data, trainer.previous_random_events)
|
||||
|
||||
if previous_random_event
|
||||
event_message_map = {
|
||||
CATCH: trainer_data.preRematchText_caught,
|
||||
EVOLVE: trainer_data.preRematchText_evolved,
|
||||
FUSE: trainer_data.preRematchText_fused,
|
||||
UNFUSE: trainer_data.preRematchText_unfused,
|
||||
REVERSE: trainer_data.preRematchText_reversed
|
||||
}
|
||||
|
||||
message_text = event_message_map[previous_random_event.eventType] || trainer_data.preRematchText
|
||||
else
|
||||
message_text = trainer_data.preRematchText
|
||||
end
|
||||
end
|
||||
|
||||
if previous_random_event
|
||||
message_text = message_text.gsub("<CAUGHT_POKEMON>", getSpeciesRealName(previous_random_event.caught_pokemon).to_s)
|
||||
message_text = message_text.gsub("<UNEVOLVED_POKEMON>", getSpeciesRealName(previous_random_event.unevolved_pokemon).to_s)
|
||||
message_text = message_text.gsub("<EVOLVED_POKEMON>", getSpeciesRealName(previous_random_event.evolved_pokemon).to_s)
|
||||
message_text = message_text.gsub("<HEAD_POKEMON>", getSpeciesRealName(previous_random_event.fusion_head_pokemon).to_s)
|
||||
message_text = message_text.gsub("<BODY_POKEMON>", getSpeciesRealName(previous_random_event.fusion_body_pokemon).to_s)
|
||||
message_text = message_text.gsub("<FUSED_POKEMON>", getSpeciesRealName(previous_random_event.fusion_fused_pokemon).to_s)
|
||||
message_text = message_text.gsub("<UNREVERSED_POKEMON>", getSpeciesRealName(previous_random_event.unreversed_pokemon).to_s)
|
||||
message_text = message_text.gsub("<REVERSED_POKEMON>", getSpeciesRealName(previous_random_event.reversed_pokemon).to_s)
|
||||
message_text = message_text.gsub("<UNFUSED_POKEMON>", getSpeciesRealName(previous_random_event.unfused_pokemon).to_s)
|
||||
else
|
||||
message_text = trainer_data.preRematchText
|
||||
end
|
||||
if message_text
|
||||
split_messages = message_text.split("<br>")
|
||||
split_messages.each do |msg|
|
||||
pbCallBub(2,event.id)
|
||||
pbMessage(msg)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,203 @@
|
||||
class StartersSelectionScene
|
||||
POKEBALL_LEFT_X = -20; POKEBALL_LEFT_Y = 70
|
||||
POKEBALL_MIDDLE_X = 125; POKEBALL_MIDDLE_Y = 100
|
||||
POKEBALL_RIGHT_X = 275; POKEBALL_RIGHT_Y = 70
|
||||
|
||||
TEXT_POSITION_X = 100
|
||||
TEXT_POSITION_Y = 10
|
||||
|
||||
def initialize(starters = [])
|
||||
@starters_species = starters
|
||||
@starter_pokemon = []
|
||||
@starters_species.each do |species|
|
||||
@starter_pokemon.push(Pokemon.new(species,5))
|
||||
end
|
||||
|
||||
@spritesLoader = BattleSpriteLoader.new
|
||||
@shown_starter_species=nil
|
||||
end
|
||||
|
||||
def initializeGraphics()
|
||||
@background = displayPicture("Graphics/Pictures/Trades/hoenn_starter_bag_bg.png", -20, -20)
|
||||
@background.z=0
|
||||
|
||||
@foreground = displayPicture("Graphics/Pictures/Trades/hoenn_starter_bag_foreground.png", -20, -20)
|
||||
@foreground.z=999
|
||||
|
||||
@pokeball_closed_left = displayPicture("Graphics/Pictures/Trades/trade_pokeball_closed_1.png", POKEBALL_LEFT_X, POKEBALL_LEFT_Y)
|
||||
@pokeball_closed_left.z=2
|
||||
|
||||
@pokeball_closed_middle = displayPicture("Graphics/Pictures/Trades/trade_pokeball_closed_2.png", POKEBALL_MIDDLE_X, POKEBALL_MIDDLE_Y)
|
||||
@pokeball_closed_middle.z=100
|
||||
|
||||
@pokeball_closed_right = displayPicture("Graphics/Pictures/Trades/trade_pokeball_closed_3.png", POKEBALL_RIGHT_X, POKEBALL_RIGHT_Y)
|
||||
@pokeball_closed_right.z=2
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
def updateOpenPokeballPosition
|
||||
case @index
|
||||
when 0
|
||||
@shown_pokemon_x = POKEBALL_LEFT_X
|
||||
@shown_pokemon_y = POKEBALL_LEFT_Y
|
||||
when 1
|
||||
@shown_pokemon_x = POKEBALL_MIDDLE_X
|
||||
@shown_pokemon_y = POKEBALL_MIDDLE_Y
|
||||
when 2
|
||||
@shown_pokemon_x = POKEBALL_RIGHT_X
|
||||
@shown_pokemon_y = POKEBALL_RIGHT_Y
|
||||
end
|
||||
end
|
||||
|
||||
def startScene
|
||||
initializeGraphics
|
||||
@index=nil
|
||||
previous_index = nil
|
||||
loop do
|
||||
if @index
|
||||
if Input.trigger?(Input::RIGHT)
|
||||
previous_index = @index
|
||||
@index+=1
|
||||
@index = 0 if @index == @starters_species.length
|
||||
end
|
||||
if Input.trigger?(Input::LEFT)
|
||||
previous_index = @index
|
||||
@index-=1
|
||||
@index = @starters_species.length-1 if @index < 0
|
||||
end
|
||||
if Input.trigger?(Input::UP) || Input.trigger?(Input::DOWN)
|
||||
updateOpenPokeballPosition
|
||||
updateStarterSelectionGraphics
|
||||
end
|
||||
|
||||
if Input.trigger?(Input::USE)
|
||||
if pbConfirmMessage(_INTL("Do you choose this Pokémon?"))
|
||||
chosenPokemon = @starter_pokemon[@index]
|
||||
@spritesLoader.registerSpriteSubstitution(@pif_sprite)
|
||||
disposeGraphics
|
||||
pbSet(VAR_HOENN_CHOSEN_STARTER_INDEX,@index)
|
||||
return chosenPokemon
|
||||
end
|
||||
end
|
||||
else
|
||||
@index = 0 if Input.trigger?(Input::LEFT)
|
||||
@index = 1 if Input.trigger?(Input::DOWN)
|
||||
@index = 2 if Input.trigger?(Input::RIGHT)
|
||||
end
|
||||
|
||||
if previous_index != @index
|
||||
updateOpenPokeballPosition
|
||||
updateStarterSelectionGraphics
|
||||
previous_index = @index
|
||||
end
|
||||
Input.update
|
||||
Graphics.update
|
||||
end
|
||||
end
|
||||
|
||||
def disposeGraphics()
|
||||
@pokeball_closed_left.dispose
|
||||
@pokeball_closed_middle.dispose
|
||||
@pokeball_closed_right.dispose
|
||||
@pokeball_open_back.dispose
|
||||
@pokeball_open_front.dispose
|
||||
@background.dispose
|
||||
@foreground.dispose
|
||||
@pokemon_name_overlay.dispose
|
||||
@pokemon_category_overlay.dispose
|
||||
@pokemonSpriteWindow.dispose
|
||||
end
|
||||
|
||||
def updateClosedBallGraphicsVisibility
|
||||
case @index
|
||||
when 0
|
||||
@pokeball_closed_left.visible=false
|
||||
@pokeball_closed_middle.visible=true
|
||||
@pokeball_closed_right.visible=true
|
||||
when 1
|
||||
@pokeball_closed_left.visible=true
|
||||
@pokeball_closed_middle.visible=false
|
||||
@pokeball_closed_right.visible=true
|
||||
when 2
|
||||
@pokeball_closed_left.visible=true
|
||||
@pokeball_closed_middle.visible=true
|
||||
@pokeball_closed_right.visible=false
|
||||
else
|
||||
@pokeball_closed_left.visible=true
|
||||
@pokeball_closed_middle.visible=true
|
||||
@pokeball_closed_right.visible=true
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
def updateStarterSelectionGraphics()
|
||||
pbSEPlay("GUI storage pick up", 80, 100)
|
||||
updateClosedBallGraphicsVisibility
|
||||
@pokeball_open_back.dispose if @pokeball_open_back
|
||||
@pokeball_open_front.dispose if @pokeball_open_front
|
||||
|
||||
@shown_starter_species = @starters_species[@index]
|
||||
|
||||
updateOpenPokeballPosition
|
||||
@pokeball_open_back = displayPicture("Graphics/Pictures/Trades/trade_pokeball_open_back",@shown_pokemon_x, @shown_pokemon_y,2)
|
||||
@pokeball_open_front = displayPicture("Graphics/Pictures/Trades/trade_pokeball_open_front",@shown_pokemon_x, @shown_pokemon_y,50)
|
||||
|
||||
updatePokemonSprite
|
||||
end
|
||||
|
||||
def updatePokemonSprite()
|
||||
@pif_sprite = @spritesLoader.get_pif_sprite_from_species(@shown_starter_species.species)
|
||||
sprite_bitmap = @spritesLoader.load_pif_sprite_directly(@pif_sprite)
|
||||
pokemon = @starter_pokemon[@index]
|
||||
if pokemon.shiny?
|
||||
sprite_bitmap.bitmap.update_shiny_cache(pokemon.id_number, "")
|
||||
sprite_bitmap.shiftAllColors(pokemon.id_number, pokemon.bodyShiny?, pokemon.headShiny?)
|
||||
end
|
||||
|
||||
@pokemonSpriteWindow.dispose if @pokemonSpriteWindow
|
||||
@pokemonSpriteWindow = PictureWindow.new(sprite_bitmap.bitmap)
|
||||
|
||||
@pokemonSpriteWindow.opacity = 0
|
||||
@pokemonSpriteWindow.z = 2
|
||||
@pokemonSpriteWindow.x = @shown_pokemon_x
|
||||
@pokemonSpriteWindow.y = @shown_pokemon_y-10
|
||||
updateText
|
||||
end
|
||||
|
||||
def updateText
|
||||
@pokemon_name_overlay.dispose if @pokemon_name_overlay
|
||||
@pokemon_category_overlay.dispose if @pokemon_category_overlay
|
||||
|
||||
pokemon_name = "#{@shown_starter_species.real_name}"
|
||||
pokemon_category = "#{@shown_starter_species.real_category} Pokémon"
|
||||
|
||||
title_position_y = TEXT_POSITION_Y
|
||||
subtitle_position_y = TEXT_POSITION_Y + 30
|
||||
|
||||
text_x_offset=-100
|
||||
|
||||
label_base_color = Color.new(88,88,80)
|
||||
label_shadow_color = Color.new(168,184,184)
|
||||
|
||||
title_base_color = Color.new(248, 248, 248)
|
||||
title_shadow_color = Color.new(104, 104, 104)
|
||||
|
||||
@pokemon_name_overlay = BitmapSprite.new(Graphics.width, Graphics.height, @viewport).bitmap
|
||||
@pokemon_category_overlay = BitmapSprite.new(Graphics.width, Graphics.height, @viewport).bitmap
|
||||
|
||||
@pokemon_name_overlay.font.size = 50
|
||||
@pokemon_name_overlay.font.name = MessageConfig.pbGetSmallFontName
|
||||
|
||||
@pokemon_category_overlay.font.size = 36
|
||||
@pokemon_category_overlay.font.name = MessageConfig.pbGetSmallFontName
|
||||
|
||||
pbDrawTextPositions(@pokemon_name_overlay, [[pokemon_name, (Graphics.width/2)+text_x_offset, title_position_y, 2, title_base_color, title_shadow_color]])
|
||||
pbDrawTextPositions(@pokemon_category_overlay,[[pokemon_category, (Graphics.width/2)+text_x_offset, subtitle_position_y, 2, label_base_color, label_shadow_color]])
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
class BattledTrainer
|
||||
TRAINER_CLASS_FAVORITE_TYPES =
|
||||
{
|
||||
AROMALADY: [:GRASS, :FAIRY],
|
||||
BEAUTY: [:FAIRY, :WATER, :NORMAL, :GRASS],
|
||||
BIKER: [:POISON, :DARK],
|
||||
BIRDKEEPER: [:FLYING, :NORMAL],
|
||||
BUGCATCHER: [:BUG],
|
||||
BURGLAR: [:FIRE, :DARK],
|
||||
CHANNELER: [:GHOST, :PSYCHIC],
|
||||
CUEBALL: [:FIGHTING],
|
||||
ENGINEER: [:ELECTRIC, :STEEL],
|
||||
FISHERMAN: [:WATER],
|
||||
GAMBLER: [:NORMAL, :PSYCHIC],
|
||||
GENTLEMAN: [:NORMAL, :STEEL],
|
||||
HIKER: [:ROCK, :GROUND],
|
||||
JUGGLER: [:PSYCHIC, :GHOST],
|
||||
LADY: [:FAIRY, :NORMAL],
|
||||
PAINTER: [:NORMAL, :PSYCHIC],
|
||||
POKEMANIAC: [:DRAGON, :GROUND],
|
||||
POKEMONBREEDER: [:NORMAL, :GRASS],
|
||||
PROFESSOR: [:NORMAL, :PSYCHIC],
|
||||
ROCKER: [:ELECTRIC, :FIRE],
|
||||
RUINMANIAC: [:GROUND, :ROCK],
|
||||
SAILOR: [:WATER, :FIGHTING],
|
||||
SCIENTIST: [:ELECTRIC, :STEEL, :POISON],
|
||||
SUPERNERD: [:ELECTRIC, :PSYCHIC, :STEEL],
|
||||
TAMER: [:NORMAL, :DARK],
|
||||
BLACKBELT: [:FIGHTING],
|
||||
CRUSHGIRL: [:FIGHTING],
|
||||
CAMPER: [:BUG, :NORMAL, :GRASS],
|
||||
PICNICKER: [:GRASS, :NORMAL],
|
||||
COOLTRAINER_M: [:DRAGON, :STEEL, :FIRE],
|
||||
COOLTRAINER_F: [:ICE, :PSYCHIC, :FAIRY],
|
||||
YOUNGSTER: [:NORMAL, :BUG],
|
||||
LASS: [:NORMAL, :FAIRY],
|
||||
POKEMONRANGER_M: [:GRASS, :GROUND],
|
||||
POKEMONRANGER_F: [:GRASS, :WATER],
|
||||
PSYCHIC_M: [:PSYCHIC, :GHOST],
|
||||
PSYCHIC_F: [:PSYCHIC, :FAIRY],
|
||||
SWIMMER_M: [:WATER],
|
||||
SWIMMER_F: [:WATER, :ICE],
|
||||
SWIMMER2_M: [:WATER],
|
||||
SWIMMER2_F: [:WATER],
|
||||
TUBER_M: [:WATER],
|
||||
TUBER_F: [:WATER],
|
||||
TUBER2_M: [:WATER],
|
||||
TUBER2_F: [:WATER],
|
||||
COOLCOUPLE: [:FIRE, :ICE],
|
||||
CRUSHKIN: [:FIGHTING],
|
||||
SISANDBRO: [:WATER, :GROUND],
|
||||
TWINS: [:FAIRY, :NORMAL],
|
||||
YOUNGCOUPLE: [:NORMAL, :PSYCHIC],
|
||||
SOCIALITE: [:FAIRY, :NORMAL],
|
||||
BUGCATCHER_F: [:BUG],
|
||||
ROUGHNECK: [:DARK, :FIGHTING],
|
||||
TEACHER: [:PSYCHIC, :NORMAL],
|
||||
PRESCHOOLER_M: [:NORMAL],
|
||||
PRESCHOOLER_F: [:FAIRY, :NORMAL],
|
||||
HAUNTEDGIRL_YOUNG: [:GHOST],
|
||||
HAUNTEDGIRL: [:GHOST, :DARK],
|
||||
CLOWN: [:PSYCHIC, :FAIRY],
|
||||
NURSE: [:NORMAL, :FAIRY],
|
||||
WORKER: [:STEEL, :GROUND],
|
||||
COOLTRAINER_M2: [:FIGHTING, :STEEL],
|
||||
COOLTRAINER_F2: [:PSYCHIC, :ICE],
|
||||
FARMER: [:GRASS, :GROUND, :NORMAL],
|
||||
PYROMANIAC: [:FIRE],
|
||||
KIMONOGIRL: [:FAIRY, :PSYCHIC, :GHOST],
|
||||
SAGE: [:PSYCHIC, :GHOST],
|
||||
PLAYER: [:ICE, :FIGHTING],
|
||||
POLICE: [:DARK, :FIGHTING],
|
||||
SKIER_F: [:ICE],
|
||||
DELIVERYMAN: [:NORMAL],
|
||||
RICHBOY: [],
|
||||
SCHOOLBOY: [],
|
||||
SCHOOLGIRL: [],
|
||||
TEAM_AQUA_GRUNT_M: [],
|
||||
TEAM_AQUA_GRUNT_F: [],
|
||||
TEAM_MAGMA_GRUNT_M: [],
|
||||
TEAM_MAGMA_GRUNT_F: [],
|
||||
TEAM_MAGMAQUA_GRUNT_M: [],
|
||||
TEAM_MAGMAQUA_GRUNT_F: [],
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
class BattledTrainer
|
||||
FRIENDSHIP_LEVELS = {
|
||||
AROMALADY: [10, 25, 45],
|
||||
BEAUTY: [15, 30, 60],
|
||||
BIKER: [20, 40, 80],
|
||||
BIRDKEEPER: [10, 25, 50],
|
||||
BUGCATCHER: [8, 20, 35],
|
||||
BURGLAR: [20, 45, 90],
|
||||
CHANNELER: [15, 35, 70],
|
||||
CUEBALL: [18, 38, 80],
|
||||
ENGINEER: [15, 30, 65],
|
||||
FISHERMAN: [12, 28, 55],
|
||||
GAMBLER: [15, 30, 60],
|
||||
GENTLEMAN: [12, 30, 70],
|
||||
HIKER: [10, 25, 50],
|
||||
JUGGLER: [15, 30, 65],
|
||||
LADY: [15, 30, 60],
|
||||
PAINTER: [8, 22, 40],
|
||||
POKEMANIAC: [18, 35, 70],
|
||||
POKEMONBREEDER: [8, 18, 35],
|
||||
PROFESSOR: [10, 30, 60],
|
||||
ROCKER: [15, 35, 70],
|
||||
RUINMANIAC: [15, 35, 65],
|
||||
SAILOR: [12, 28, 60],
|
||||
SCIENTIST: [15, 35, 70],
|
||||
SUPERNERD: [14, 30, 65],
|
||||
TAMER: [15, 35, 75],
|
||||
BLACKBELT: [20, 45, 90],
|
||||
CRUSHGIRL: [18, 40, 85],
|
||||
CAMPER: [10, 22, 40],
|
||||
PICNICKER: [10, 22, 40],
|
||||
COOLTRAINER_M: [20, 45, 95],
|
||||
COOLTRAINER_F: [20, 45, 95],
|
||||
YOUNGSTER: [10, 25, 40],
|
||||
LASS: [10, 22, 38],
|
||||
POKEMONRANGER_M:[15, 35, 80],
|
||||
POKEMONRANGER_F:[15, 35, 80],
|
||||
PSYCHIC_M: [15, 35, 70],
|
||||
PSYCHIC_F: [15, 35, 70],
|
||||
SWIMMER_M: [10, 25, 50],
|
||||
SWIMMER_F: [10, 25, 50],
|
||||
SWIMMER2_M: [12, 28, 55],
|
||||
SWIMMER2_F: [12, 28, 55],
|
||||
TUBER_M: [6, 15, 30],
|
||||
TUBER_F: [6, 15, 30],
|
||||
TUBER2_M: [6, 15, 30],
|
||||
TUBER2_F: [6, 15, 30],
|
||||
COOLCOUPLE: [15, 35, 80],
|
||||
CRUSHKIN: [15, 35, 80],
|
||||
SISANDBRO: [10, 25, 50],
|
||||
TWINS: [10, 25, 50],
|
||||
YOUNGCOUPLE: [15, 30, 65],
|
||||
SOCIALITE: [12, 30, 70],
|
||||
BUGCATCHER_F: [8, 20, 35],
|
||||
ROUGHNECK: [18, 38, 85],
|
||||
TEACHER: [12, 28, 60],
|
||||
PRESCHOOLER_M: [5, 12, 25],
|
||||
PRESCHOOLER_F: [5, 12, 25],
|
||||
HAUNTEDGIRL_YOUNG: [10, 25, 55],
|
||||
HAUNTEDGIRL: [12, 30, 65],
|
||||
CLOWN: [10, 25, 50],
|
||||
NURSE: [8, 20, 35],
|
||||
WORKER: [12, 30, 65],
|
||||
COOLTRAINER_M2: [22, 50, 100],
|
||||
COOLTRAINER_F2: [22, 50, 100],
|
||||
FARMER: [10, 25, 50],
|
||||
PYROMANIAC: [20, 45, 90],
|
||||
KIMONOGIRL: [12, 30, 60],
|
||||
SAGE: [15, 30, 65],
|
||||
PLAYER: [12, 30, 60],
|
||||
POLICE: [20, 45, 90],
|
||||
SKIER_F: [12, 28, 55],
|
||||
DELIVERYMAN: [8, 20, 40],
|
||||
RICHBOY: [15, 35, 70],
|
||||
SCHOOLBOY: [10, 22, 40],
|
||||
SCHOOLGIRL: [10, 22, 40],
|
||||
TEAM_AQUA_GRUNT_M: [25, 60, 100],
|
||||
TEAM_AQUA_GRUNT_F: [25, 60, 100],
|
||||
TEAM_MAGMA_GRUNT_M: [25, 60, 100],
|
||||
TEAM_MAGMA_GRUNT_F: [25, 60, 100],
|
||||
TEAM_MAGMAQUA_GRUNT_M: [25, 60, 100],
|
||||
TEAM_MAGMAQUA_GRUNT_F: [25, 60, 100],
|
||||
}
|
||||
|
||||
end
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#####
|
||||
# Util methods
|
||||
#####
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
####
|
||||
# Methods to be called from events
|
||||
####
|
||||
|
||||
|
||||
#actionType :
|
||||
# :BATTLE
|
||||
# :TRADE
|
||||
# :PARTNER
|
||||
def doPostBattleAction(actionType)
|
||||
event = pbMapInterpreter.get_character(0)
|
||||
map_id = $game_map.map_id if map_id.nil?
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
trainer.clear_previous_random_events()
|
||||
|
||||
return if !trainer
|
||||
case actionType
|
||||
when :BATTLE
|
||||
trainer = doNPCTrainerRematch(trainer)
|
||||
when :TRADE
|
||||
trainer = doNPCTrainerTrade(trainer)
|
||||
when :PARTNER
|
||||
partnerWithTrainer(event.id,map_id,trainer)
|
||||
end
|
||||
updateRebattledTrainer(event.id,map_id,trainer)
|
||||
|
||||
end
|
||||
|
||||
def setTrainerFriendship(trainer)
|
||||
params = ChooseNumberParams.new
|
||||
params.setRange(0,100)
|
||||
params.setDefaultValue($game_map.map_id)
|
||||
number = pbMessageChooseNumber("Frienship (0-100)?",params)
|
||||
trainer.friendship = number
|
||||
trainer.increase_friendship(0)
|
||||
return trainer
|
||||
end
|
||||
|
||||
#party: array of pokemon team
|
||||
# [[:SPECIES,level], ... ]
|
||||
#
|
||||
#def customTrainerBattle(trainerName, trainerType, party_array, default_level=50, endSpeech="", sprite_override=nil,custom_appearance=nil)
|
||||
def postBattleActionsMenu()
|
||||
rematchCommand = "Rematch"
|
||||
tradeCommand = "Trade Offer"
|
||||
partnerCommand = "Partner up"
|
||||
cancelCommand = "See ya!"
|
||||
|
||||
updateTeamDebugCommand = "(Debug) Simulate random event"
|
||||
resetTrainerDebugCommand = "(Debug) Reset trainer"
|
||||
setFriendshipDebugCommand = "(Debug) Set Friendship"
|
||||
printTrainerTeamDebugCommand = "(Debug) Print team"
|
||||
|
||||
|
||||
event = pbMapInterpreter.get_character(0)
|
||||
map_id = $game_map.map_id if map_id.nil?
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
|
||||
options = []
|
||||
options << rematchCommand
|
||||
options << tradeCommand if trainer.friendship_level >= 1
|
||||
options << partnerCommand if trainer.friendship_level >= 3
|
||||
|
||||
options << updateTeamDebugCommand if $DEBUG
|
||||
options << resetTrainerDebugCommand if $DEBUG
|
||||
options << setFriendshipDebugCommand if $DEBUG
|
||||
options << printTrainerTeamDebugCommand if $DEBUG
|
||||
|
||||
options << cancelCommand
|
||||
|
||||
trainer = applyTrainerRandomEvents(trainer)
|
||||
showPrerematchDialog
|
||||
choice = optionsMenu(options,options.find_index(cancelCommand),options.find_index(cancelCommand))
|
||||
|
||||
case options[choice]
|
||||
when rematchCommand
|
||||
doPostBattleAction(:BATTLE)
|
||||
when tradeCommand
|
||||
doPostBattleAction(:TRADE)
|
||||
when partnerCommand
|
||||
doPostBattleAction(:PARTNER)
|
||||
when updateTeamDebugCommand
|
||||
echoln("")
|
||||
echoln "---------------"
|
||||
makeRebattledTrainerTeamGainExp(trainer,true)
|
||||
evolveRebattledTrainerPokemon(trainer)
|
||||
applyTrainerRandomEvents(trainer)
|
||||
when resetTrainerDebugCommand
|
||||
resetTrainerRebattle(event.id,map_id)
|
||||
when setFriendshipDebugCommand
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
trainer = setTrainerFriendship(trainer)
|
||||
updateRebattledTrainer(event.id,map_id,trainer)
|
||||
when printTrainerTeamDebugCommand
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
printNPCTrainerCurrentTeam(trainer)
|
||||
when cancelCommand
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
COMMON_EVENT_TRAINER_REMATCH_PARTNER = 200
|
||||
def partnerWithTrainer(eventId, mapID, trainer)
|
||||
Kernel.pbAddDependency2(eventId,trainer.trainerName,COMMON_EVENT_TRAINER_REMATCH_PARTNER)
|
||||
pbCancelVehicles
|
||||
originalTrainer = pbLoadTrainer(trainer.trainerType, trainer.trainerName, 0)
|
||||
Events.onTrainerPartyLoad.trigger(nil, originalTrainer)
|
||||
for i in trainer.currentTeam
|
||||
i.owner = Pokemon::Owner.new_from_trainer(originalTrainer)
|
||||
i.calc_stats
|
||||
end
|
||||
$PokemonGlobal.partner = [trainer.trainerType, trainer.trainerName, 0, trainer.currentTeam]
|
||||
end
|
||||
@@ -0,0 +1,195 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
def printNPCTrainerCurrentTeam(trainer)
|
||||
team_string = "["
|
||||
trainer.currentTeam.each do |pokemon|
|
||||
name= get_pokemon_readable_internal_name(pokemon)
|
||||
level = pokemon.level
|
||||
formatted_info = "#{name} (lv.#{level}), "
|
||||
team_string += formatted_info
|
||||
end
|
||||
team_string += "]"
|
||||
echoln "Trainer's current team is: #{team_string}"
|
||||
end
|
||||
|
||||
def applyTrainerRandomEvents(trainer)
|
||||
if trainer.has_pending_action
|
||||
echoln "Trainer has pending action"
|
||||
end
|
||||
|
||||
return trainer if trainer.has_pending_action
|
||||
trainer.clear_previous_random_events
|
||||
|
||||
#time_passed = trainer.getTimeSinceLastAction
|
||||
#return trainer if time_passed < TIME_FOR_RANDOM_EVENTS
|
||||
|
||||
# Weighted chances out of 10
|
||||
weighted_events = [
|
||||
[:CATCH, 3],
|
||||
[:FUSE, 6],
|
||||
[:REVERSE, 1],
|
||||
[:UNFUSE, 20]
|
||||
]
|
||||
|
||||
# Create a flat array of events based on weight
|
||||
event_pool = weighted_events.flat_map { |event, weight| [event] * weight }
|
||||
|
||||
selected_event = event_pool.sample
|
||||
|
||||
if selected_event
|
||||
echoln "Trying to do random event: #{selected_event}"
|
||||
end
|
||||
|
||||
|
||||
return trainer if selected_event.nil?
|
||||
|
||||
case selected_event
|
||||
when :CATCH
|
||||
trainer = catch_new_team_pokemon(trainer)
|
||||
when :FUSE
|
||||
trainer = fuse_random_team_pokemon(trainer)
|
||||
when :UNFUSE
|
||||
trainer = unfuse_random_team_pokemon(trainer)
|
||||
when :REVERSE
|
||||
trainer = reverse_random_team_pokemon(trainer)
|
||||
end
|
||||
trainer.set_pending_action(true)
|
||||
printNPCTrainerCurrentTeam(trainer)
|
||||
return trainer
|
||||
end
|
||||
|
||||
|
||||
|
||||
def chooseEncounterType(trainerClass)
|
||||
water_trainer_classes = [:SWIMMER_F, :SWIMMER_M, :FISHERMAN]
|
||||
if water_trainer_classes.include?(trainerClass )
|
||||
chance_of_land_encounter = 1
|
||||
chance_of_surf_encounter= 5
|
||||
chance_of_cave_encounter = 1
|
||||
chance_of_fishing_encounter = 5
|
||||
else
|
||||
chance_of_land_encounter = 5
|
||||
chance_of_surf_encounter= 1
|
||||
chance_of_cave_encounter = 5
|
||||
chance_of_fishing_encounter = 1
|
||||
end
|
||||
|
||||
if pbCheckHiddenMoveBadge(Settings::BADGE_FOR_SURF, false)
|
||||
chance_of_surf_encounter =0
|
||||
chance_of_fishing_encounter = 0
|
||||
end
|
||||
|
||||
possible_encounter_types = []
|
||||
if $PokemonEncounters.has_land_encounters?
|
||||
possible_encounter_types += [:Land] * chance_of_land_encounter
|
||||
end
|
||||
if $PokemonEncounters.has_cave_encounters?
|
||||
possible_encounter_types += [:Cave] * chance_of_cave_encounter
|
||||
end
|
||||
if $PokemonEncounters.has_water_encounters?
|
||||
possible_encounter_types += [:GoodRod] * chance_of_fishing_encounter
|
||||
possible_encounter_types += [:Water] * chance_of_surf_encounter
|
||||
end
|
||||
echoln "possible_encounter_types: #{possible_encounter_types}"
|
||||
return getTimeBasedEncounter(possible_encounter_types.sample)
|
||||
end
|
||||
|
||||
|
||||
def getTimeBasedEncounter(encounter_type)
|
||||
time = pbGetTimeNow
|
||||
return $PokemonEncounters.find_valid_encounter_type_for_time(encounter_type, time)
|
||||
end
|
||||
|
||||
def catch_new_team_pokemon(trainer)
|
||||
return trainer if trainer.currentTeam.length >= 6
|
||||
encounter_type = chooseEncounterType(trainer.trainerType)
|
||||
return trainer if !encounter_type
|
||||
|
||||
echoln "Catching a pokemon via encounter_type #{encounter_type}"
|
||||
wild_pokemon = $PokemonEncounters.choose_wild_pokemon(encounter_type)
|
||||
echoln wild_pokemon
|
||||
if wild_pokemon
|
||||
trainer.currentTeam << Pokemon.new(wild_pokemon[0],wild_pokemon[1])
|
||||
trainer.log_catch_event(wild_pokemon[0])
|
||||
end
|
||||
return trainer
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def reverse_random_team_pokemon(trainer)
|
||||
eligible_pokemon = trainer.list_team_fused_pokemon
|
||||
return trainer if eligible_pokemon.length < 1
|
||||
return trainer if trainer.currentTeam.length > 5
|
||||
pokemon_to_reverse = eligible_pokemon.sample
|
||||
old_species = pokemon_to_reverse.species
|
||||
trainer.currentTeam.delete(pokemon_to_reverse)
|
||||
|
||||
body_pokemon = get_body_species_from_symbol(pokemon_to_reverse.species)
|
||||
head_pokemon = get_head_species_from_symbol(pokemon_to_reverse.species)
|
||||
|
||||
pokemon_to_reverse.species = getFusedPokemonIdFromSymbols(head_pokemon,body_pokemon)
|
||||
trainer.currentTeam.push(pokemon_to_reverse)
|
||||
trainer.log_reverse_event(old_species,pokemon_to_reverse.species)
|
||||
return trainer
|
||||
end
|
||||
|
||||
|
||||
def unfuse_random_team_pokemon(trainer)
|
||||
eligible_pokemon = trainer.list_team_fused_pokemon
|
||||
return trainer if eligible_pokemon.length < 1
|
||||
return trainer if trainer.currentTeam.length > 5
|
||||
pokemon_to_unfuse = eligible_pokemon.sample
|
||||
|
||||
echoln pokemon_to_unfuse.owner.name
|
||||
echoln trainer.trainerName
|
||||
return trainer if pokemon_to_unfuse.owner.name != trainer.trainerName
|
||||
|
||||
body_pokemon = get_body_id_from_symbol(pokemon_to_unfuse.species)
|
||||
head_pokemon = get_head_id_from_symbol(pokemon_to_unfuse.species)
|
||||
|
||||
level = calculateUnfuseLevelOldMethod(pokemon_to_unfuse,false)
|
||||
|
||||
trainer.currentTeam.delete(pokemon_to_unfuse)
|
||||
trainer.currentTeam.push(Pokemon.new(body_pokemon,level))
|
||||
trainer.currentTeam.push(Pokemon.new(head_pokemon,level))
|
||||
trainer.log_unfusion_event(pokemon_to_unfuse.species, body_pokemon, head_pokemon)
|
||||
return trainer
|
||||
end
|
||||
|
||||
def fuse_random_team_pokemon(trainer)
|
||||
eligible_pokemon = trainer.list_team_unfused_pokemon
|
||||
return trainer if eligible_pokemon.length < 2
|
||||
|
||||
pokemon_to_fuse = eligible_pokemon.sample(2)
|
||||
body_pokemon = pokemon_to_fuse[0]
|
||||
head_pokemon = pokemon_to_fuse[1]
|
||||
fusion_species = getFusedPokemonIdFromSymbols(body_pokemon.species,head_pokemon.species)
|
||||
level = (body_pokemon.level + head_pokemon.level)/2
|
||||
fused_pokemon = Pokemon.new(fusion_species,level)
|
||||
|
||||
trainer.currentTeam.delete(body_pokemon)
|
||||
trainer.currentTeam.delete(head_pokemon)
|
||||
trainer.currentTeam.push(fused_pokemon)
|
||||
trainer.log_fusion_event(body_pokemon.species,head_pokemon.species,fusion_species)
|
||||
return trainer
|
||||
end
|
||||
|
||||
def getBestMatchingPreviousRandomEvent(trainer_data, previous_events)
|
||||
return nil if trainer_data.nil? || previous_events.nil?
|
||||
|
||||
priority = [:CATCH, :EVOLVE, :FUSE, :UNFUSE, :REVERSE]
|
||||
event_message_map = {
|
||||
CATCH: trainer_data.preRematchText_caught,
|
||||
EVOLVE: trainer_data.preRematchText_evolved,
|
||||
FUSE: trainer_data.preRematchText_fused,
|
||||
UNFUSE: trainer_data.preRematchText_unfused,
|
||||
REVERSE: trainer_data.preRematchText_reversed
|
||||
}
|
||||
sorted_events = previous_events.sort_by do |event|
|
||||
priority.index(event.eventType) || Float::INFINITY
|
||||
end
|
||||
|
||||
sorted_events.find { |event| event_message_map[event.eventType] }
|
||||
end
|
||||
@@ -0,0 +1,273 @@
|
||||
|
||||
TRAINER_CLASS_FAVORITE_TYPES =
|
||||
{
|
||||
AROMALADY: [:GRASS, :FAIRY],
|
||||
BEAUTY: [:FAIRY, :WATER, :NORMAL, :GRASS],
|
||||
BIKER: [:POISON, :DARK],
|
||||
BIRDKEEPER: [:FLYING, :NORMAL],
|
||||
BUGCATCHER: [:BUG],
|
||||
BURGLAR: [:FIRE, :DARK],
|
||||
CHANNELER: [:GHOST, :PSYCHIC],
|
||||
CUEBALL: [:FIGHTING, :STEEL],
|
||||
ENGINEER: [:ELECTRIC, :STEEL],
|
||||
FISHERMAN: [:WATER],
|
||||
GAMBLER: [:NORMAL, :PSYCHIC],
|
||||
GENTLEMAN: [:NORMAL, :STEEL],
|
||||
HIKER: [:ROCK, :GROUND],
|
||||
JUGGLER: [:PSYCHIC, :GHOST, :NORMAL, :POISON],
|
||||
LADY: [:FAIRY, :NORMAL],
|
||||
PAINTER: [:NORMAL, :PSYCHIC, :GRASS],
|
||||
POKEMANIAC: [:DRAGON, :GROUND],
|
||||
POKEMONBREEDER: [:NORMAL, :GRASS],
|
||||
PROFESSOR: [:NORMAL, :PSYCHIC],
|
||||
ROCKER: [:ELECTRIC, :FIRE],
|
||||
RUINMANIAC: [:GROUND, :ROCK, :PSYCHIC],
|
||||
SAILOR: [:WATER, :FIGHTING],
|
||||
SCIENTIST: [:ELECTRIC, :STEEL, :POISON],
|
||||
SUPERNERD: [:ELECTRIC, :PSYCHIC, :STEEL],
|
||||
TAMER: [:NORMAL, :DARK],
|
||||
BLACKBELT: [:FIGHTING],
|
||||
CRUSHGIRL: [:FIGHTING],
|
||||
CAMPER: [:BUG, :NORMAL, :GRASS],
|
||||
PICNICKER: [:GRASS, :NORMAL],
|
||||
COOLTRAINER_M: [:DRAGON, :STEEL, :FIRE],
|
||||
COOLTRAINER_F: [:ICE, :PSYCHIC, :FAIRY],
|
||||
YOUNGSTER: [:NORMAL, :BUG, :GRASS, :FLYING],
|
||||
LASS: [:NORMAL, :FAIRY],
|
||||
POKEMONRANGER_M: [:GRASS, :GROUND],
|
||||
POKEMONRANGER_F: [:GRASS, :WATER],
|
||||
PSYCHIC_M: [:PSYCHIC, :GHOST],
|
||||
PSYCHIC_F: [:PSYCHIC, :FAIRY],
|
||||
SWIMMER_M: [:WATER, :ICE],
|
||||
SWIMMER_F: [:WATER, :ICE],
|
||||
SWIMMER2_M: [:WATER],
|
||||
SWIMMER2_F: [:WATER],
|
||||
TUBER_M: [:WATER],
|
||||
TUBER_F: [:WATER],
|
||||
TUBER2_M: [:WATER],
|
||||
TUBER2_F: [:WATER],
|
||||
COOLCOUPLE: [:FIRE, :ICE],
|
||||
CRUSHKIN: [:FIGHTING],
|
||||
SISANDBRO: [:WATER, :GROUND],
|
||||
TWINS: [:FAIRY, :NORMAL],
|
||||
YOUNGCOUPLE: [:NORMAL, :PSYCHIC],
|
||||
SOCIALITE: [:FAIRY, :NORMAL],
|
||||
BUGCATCHER_F: [:BUG],
|
||||
ROUGHNECK: [:DARK, :FIGHTING],
|
||||
TEACHER: [:PSYCHIC, :NORMAL],
|
||||
PRESCHOOLER_M: [:NORMAL, :BUG],
|
||||
PRESCHOOLER_F: [:FAIRY, :NORMAL],
|
||||
HAUNTEDGIRL_YOUNG: [:GHOST],
|
||||
HAUNTEDGIRL: [:GHOST, :DARK],
|
||||
CLOWN: [:PSYCHIC, :FAIRY],
|
||||
NURSE: [:NORMAL, :FAIRY],
|
||||
WORKER: [:STEEL, :GROUND],
|
||||
COOLTRAINER_M2: [:FIGHTING, :STEEL],
|
||||
COOLTRAINER_F2: [:PSYCHIC, :ICE],
|
||||
FARMER: [:GRASS, :GROUND, :NORMAL],
|
||||
PYROMANIAC: [:FIRE],
|
||||
KIMONOGIRL: [:FAIRY, :PSYCHIC, :GHOST],
|
||||
SAGE: [:PSYCHIC, :GHOST],
|
||||
PLAYER: [:ICE, :FIGHTING],
|
||||
POLICE: [:DARK, :FIGHTING],
|
||||
SKIER_F: [:ICE],
|
||||
DELIVERYMAN: [:NORMAL],
|
||||
}
|
||||
|
||||
#Higher values: pickier
|
||||
TRAINER_CLASS_PICKINESS = {
|
||||
AROMALADY: 1.8,
|
||||
BEAUTY: 2.2,
|
||||
BIKER: 1.2,
|
||||
BIRDKEEPER: 1.4,
|
||||
BUGCATCHER: 1.1,
|
||||
BURGLAR: 1.3,
|
||||
CHANNELER: 1.7,
|
||||
CUEBALL: 1.3,
|
||||
ENGINEER: 2.0,
|
||||
FISHERMAN: 1.4,
|
||||
GAMBLER: 1.5,
|
||||
GENTLEMAN: 2.3,
|
||||
HIKER: 1.5,
|
||||
JUGGLER: 1.8,
|
||||
LADY: 2.4,
|
||||
PAINTER: 2.0,
|
||||
POKEMANIAC: 1.6,
|
||||
POKEMONBREEDER: 1.9,
|
||||
PROFESSOR: 2.5,
|
||||
ROCKER: 1.4,
|
||||
RUINMANIAC: 1.5,
|
||||
SAILOR: 1.3,
|
||||
SCIENTIST: 2.0,
|
||||
SUPERNERD: 1.9,
|
||||
TAMER: 1.5,
|
||||
BLACKBELT: 1.7,
|
||||
CRUSHGIRL: 1.6,
|
||||
CAMPER: 1.2,
|
||||
PICNICKER: 1.2,
|
||||
COOLTRAINER_M: 2.4,
|
||||
COOLTRAINER_F: 2.4,
|
||||
YOUNGSTER: 0.9,
|
||||
LASS: 1.0,
|
||||
POKEMONRANGER_M: 2.0,
|
||||
POKEMONRANGER_F: 2.0,
|
||||
PSYCHIC_M: 2.0,
|
||||
PSYCHIC_F: 2.0,
|
||||
SWIMMER_M: 1.0,
|
||||
SWIMMER_F: 1.0,
|
||||
SWIMMER2_M: 1.0,
|
||||
SWIMMER2_F: 1.0,
|
||||
TUBER_M: 0.8,
|
||||
TUBER_F: 0.8,
|
||||
TUBER2_M: 0.8,
|
||||
TUBER2_F: 0.8,
|
||||
COOLCOUPLE: 2.1,
|
||||
CRUSHKIN: 1.7,
|
||||
SISANDBRO: 1.3,
|
||||
TWINS: 1.0,
|
||||
YOUNGCOUPLE: 1.6,
|
||||
SOCIALITE: 2.3,
|
||||
BUGCATCHER_F: 1.1,
|
||||
ROUGHNECK: 1.4,
|
||||
TEACHER: 2.0,
|
||||
PRESCHOOLER_M: 0.6,
|
||||
PRESCHOOLER_F: 0.6,
|
||||
HAUNTEDGIRL_YOUNG: 1.3,
|
||||
HAUNTEDGIRL: 1.7,
|
||||
CLOWN: 1.5,
|
||||
NURSE: 2.0,
|
||||
WORKER: 1.6,
|
||||
COOLTRAINER_M2: 2.4,
|
||||
COOLTRAINER_F2: 2.4,
|
||||
FARMER: 1.5,
|
||||
PYROMANIAC: 1.6,
|
||||
KIMONOGIRL: 2.2,
|
||||
SAGE: 2.1,
|
||||
PLAYER: 1.0,
|
||||
POLICE: 1.8,
|
||||
SKIER_F: 1.6,
|
||||
DELIVERYMAN: 1.3
|
||||
}
|
||||
|
||||
|
||||
def evaluate_pokemon_worth(pkmn, compare_level: 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
|
||||
|
||||
score = level_score +
|
||||
base_stats_score +
|
||||
rarity_score +
|
||||
iv_score +
|
||||
shiny_score +
|
||||
fusion_bonus
|
||||
|
||||
echoln("#{pkmn.name} - Score : #{score}")
|
||||
return score
|
||||
end
|
||||
|
||||
|
||||
|
||||
def offerPokemonForTrade(player_pokemon, npc_party, trainer_class)
|
||||
player_score = evaluate_pokemon_worth(player_pokemon)
|
||||
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)]
|
||||
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 trainer.getTimeSinceLastTrade
|
||||
if 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)
|
||||
bg_image_id=20
|
||||
wanted_type = trainer.favorite_type
|
||||
wanted_type = :NORMAL if !wanted_type
|
||||
|
||||
wanted_type_name = GameData::Type.get(wanted_type).real_name
|
||||
trainerClassName = GameData::TrainerType.get(trainer.trainerType).real_name
|
||||
pbMessage(_INTL("#{trainerClassName} #{trainer.trainerName} is looking for \\C[1]#{wanted_type_name}-type Pokémon\\C[0]. Which Pokémon do you want to trade?."),)
|
||||
pbChoosePokemon(1,2,
|
||||
proc {|pokemon|
|
||||
pokemon.hasType?(wanted_type)
|
||||
})
|
||||
|
||||
chosen_index = pbGet(1)
|
||||
echoln pbGet(1)
|
||||
if chosen_index && chosen_index >= 0
|
||||
chosen_pokemon = $Trainer.party[chosen_index]
|
||||
offered_pokemon = offerPokemonForTrade(chosen_pokemon,trainer.currentTeam,trainer.trainerType)
|
||||
if !offered_pokemon
|
||||
pbMessage(_INTL("#{trainerClassName} #{trainer.trainerName} does not want to trade..."))
|
||||
return trainer
|
||||
end
|
||||
|
||||
pif_sprite = BattleSpriteLoader.new.get_pif_sprite_from_species(offered_pokemon.species)
|
||||
pif_sprite.dump_info()
|
||||
|
||||
message = _INTL("#{trainerClassName} #{trainer.trainerName} is offering #{offered_pokemon.name} (Level #{offered_pokemon.level}) for your #{chosen_pokemon.name}.")
|
||||
showPokemonInPokeballWithMessage(pif_sprite, message)
|
||||
|
||||
if pbConfirmMessage(_INTL("Trade away #{chosen_pokemon.name} for #{trainerClassName} #{trainer.trainerName}'s #{offered_pokemon.name}?"))
|
||||
pbStartTrade(chosen_index, offered_pokemon,offered_pokemon.name,trainer.trainerName,0)
|
||||
updated_party = trainer.currentTeam
|
||||
updated_party.delete(offered_pokemon)
|
||||
updated_party << chosen_pokemon.clone
|
||||
trainer.previous_trade_timestamp= Time.now
|
||||
trainer.increase_friendship(20)
|
||||
return trainer
|
||||
end
|
||||
end
|
||||
return trainer
|
||||
|
||||
#todo
|
||||
#
|
||||
# NPC says "I'm looking for X or Y tyflpe Pokemon (prefered Pokemon can be determined when initializing from a pool of types that depends on the trainer class)
|
||||
# Also possible to pass a list of specific Pokemon in trainers.txt that the trainer will ask for instead if it's defined
|
||||
#
|
||||
# you select one of your Pokemon and he gives you one for it
|
||||
# prioritize recently caught pokemon
|
||||
# prioritive weaker Pokemon
|
||||
#
|
||||
#Assign a score to each Pokemon in trainer's team. calculate the same score for trainer's pokemon - select which
|
||||
# one is closer
|
||||
#
|
||||
# NPC says "I can offer A in exchange for your B.
|
||||
# -Yes -> Trade, update trainer team to put the player's pokemon in there
|
||||
# Cannot trade again with the same trainer for 5 minutes
|
||||
# "You just traded with this trainer. Wait a bit before you make another offer
|
||||
# -No
|
||||
trainer.set_pending_action(false) if trainer
|
||||
return trainer
|
||||
end
|
||||
Reference in New Issue
Block a user