Rewrote BP Shop code, tidied PC menu code, fixed message display bug involving instant speed and \wtnp, fixed mail vanishing bug, tweaks to other rewritten UI

This commit is contained in:
Maruno17
2024-09-27 22:10:26 +01:00
parent 48292c2a28
commit b80de83b0d
20 changed files with 967 additions and 797 deletions

View File

@@ -128,6 +128,26 @@ module ItemHandlers
end
end
#===============================================================================
#
#===============================================================================
def pbTopRightWindow(text, scene = nil)
window = Window_AdvancedTextPokemon.new(text)
window.width = 198
window.x = Graphics.width - window.width
window.y = 0
window.z = 99999
pbPlayDecisionSE
loop do
Graphics.update
Input.update
window.update
scene&.pbUpdate
break if Input.trigger?(Input::USE)
end
window.dispose
end
#===============================================================================
#
#===============================================================================
@@ -135,12 +155,273 @@ def pbCanRegisterItem?(item)
return ItemHandlers.hasUseInFieldHandler(item)
end
def pbCanUseOnPokemon?(item)
# Returns whether pkmn is able to have an item used on it.
def pbCanPokemonHaveItemUsedOnIt?(pkmn, item)
return pkmn && !pkmn.egg? && (!pkmn.hyper_mode || GameData::Item.get(item)&.is_scent?)
end
# Used to filter the Bag when choosing an item to use on a party Pokémon.
# Also used in the Bag to indicate which party Pokémon the selected item is
# usable on.
def pbCanUseItemOnPokemon?(item)
return ItemHandlers.hasUseOnPokemon(item) ||
ItemHandlers.hasUsableOnPokemon(item) ||
GameData::Item.get(item).is_machine?
end
# This method assumes the item is usable on a Pokémon. It returns whether the
# item will have an effect when used on pkmn, i.e. it won't have no effect.
# Used in the Bag to indicate which party Pokémon the selected item is usable
# on.
def pbItemHasEffectOnPokemon?(item, pkmn)
return false if !pbCanPokemonHaveItemUsedOnIt?(pkmn, item)
ret = ItemHandlers.triggerUsableOnPokemon(item, pkmn)
return ret
end
#===============================================================================
# Use an item from the Bag and/or on a Pokémon.
#===============================================================================
# Called from the Bag screen and also when prompted to use a Repel when one runs
# out (bag_screen will be nil for the latter).
# @return [Integer] 0 = item wasn't used; 1 = item used; 2 = close Bag to use in field
def pbUseItem(bag, item, bag_screen = nil)
item_data = GameData::Item.get(item)
useType = item_data.field_use
if useType == 1 # Item is usable on a Pokémon
if $player.pokemon_count == 0
pbMessage(_INTL("There is no Pokémon."))
return 0
end
ret = false
annot = nil
if item_data.is_evolution_stone?
annot = []
$player.party.each do |pkmn|
elig = pkmn.check_evolution_on_use_item(item)
annot.push((elig) ? _INTL("ABLE") : _INTL("NOT ABLE"))
end
end
pbFadeOutIn do
screen = UI::Party.new($player.party, mode: :use_item)
if item_data.is_evolution_stone?
screen.set_able_annotation_proc(proc { |pkmn| next pkmn.check_evolution_on_use_item(item) })
end
screen.choose_pokemon do |pkmn, party_index|
next true if party_index < 0
next false if !pbCanPokemonHaveItemUsedOnIt?(pkmn, item)
qty = 1
max_at_once = ItemHandlers.triggerUseOnPokemonMaximum(item, pkmn)
max_at_once = [max_at_once, bag.quantity(item)].min
if max_at_once > 1
pbPlayDecisionSE
qty = screen.choose_number(
_INTL("How many {1} do you want to use?", GameData::Item.get(item).portion_name_plural), max_at_once
)
screen.set_help_text("")
end
next false if qty <= 0
ret = ItemHandlers.triggerUseOnPokemon(item, qty, pkmn, screen)
if ret && item_data.consumed_after_use?
bag.remove(item, qty)
if !bag.has?(item)
screen.show_message(_INTL("You used your last {1}.", item_data.portion_name))
next true
end
end
next false
end
bag_screen&.pbRefresh
end
return (ret) ? 1 : 0
elsif useType == 2 || item_data.is_machine? # Item is usable from Bag or teaches a move
intret = ItemHandlers.triggerUseFromBag(item, bag_screen)
if intret >= 0
bag.remove(item) if intret == 1 && item_data.consumed_after_use?
return intret
end
pbMessage(_INTL("Can't use that here."))
return 0
end
pbMessage(_INTL("Can't use that here."))
return 0
end
# Only called when in the party screen and having chosen an item to be used on
# the selected Pokémon.
# TODO: Replace all pbMessage and so on in here. scene is the party screen.
def pbUseItemOnPokemon(item, pkmn, scene)
item_data = GameData::Item.get(item)
# TM or HM
if item_data.is_machine?
machine = item_data.move
return false if !machine
movename = GameData::Move.get(machine).name
if pkmn.shadowPokemon?
pbMessage(_INTL("Shadow Pokémon can't be taught any moves.")) { scene.pbUpdate }
elsif !pkmn.compatible_with_move?(machine)
pbMessage(_INTL("{1} can't learn {2}.", pkmn.name, movename)) { scene.pbUpdate }
else
pbMessage("\\se[PC access]" + _INTL("You booted up the {1}.", item_data.portion_name) + "\1") { scene.pbUpdate }
if pbConfirmMessage(_INTL("Do you want to teach {1} to {2}?", movename, pkmn.name)) { scene.pbUpdate }
if pbLearnMove(pkmn, machine, false, true) { scene.pbUpdate }
$bag.remove(item) if item_data.consumed_after_use?
return true
end
end
end
return false
end
# Other item
qty = 1
max_at_once = ItemHandlers.triggerUseOnPokemonMaximum(item, pkmn)
max_at_once = [max_at_once, $bag.quantity(item)].min
if max_at_once > 1
qty = scene.scene.pbChooseNumber(
_INTL("How many {1} do you want to use?", item_data.portion_name_plural), max_at_once
)
scene.set_help_text("") if scene.is_a?(UI::Party)
end
return false if qty <= 0
ret = ItemHandlers.triggerUseOnPokemon(item, qty, pkmn, scene)
scene.clear_annotations
scene.refresh
if ret && item_data.consumed_after_use?
$bag.remove(item, qty)
if !$bag.has?(item)
pbMessage(_INTL("You used your last {1}.", item_data.portion_name)) { scene.pbUpdate }
end
end
return ret
end
def pbUseKeyItemInField(item)
ret = ItemHandlers.triggerUseInField(item)
if ret == -1 # Item effect not found
pbMessage(_INTL("Can't use that here."))
elsif ret > 0 && GameData::Item.get(item).consumed_after_use?
$bag.remove(item)
end
return ret > 0
end
def pbUseItemMessage(item)
itemname = GameData::Item.get(item).portion_name
if itemname.starts_with_vowel?
pbMessage(_INTL("You used an {1}.", itemname))
else
pbMessage(_INTL("You used a {1}.", itemname))
end
end
#===============================================================================
# Give an item to a Pokémon to hold, and take a held item from a Pokémon.
#===============================================================================
# TODO: Replace all pbDisplay and so on in here.
def pbGiveItemToPokemon(item, pkmn, scene, pkmnid = 0)
return false if item.nil?
newitemname = GameData::Item.get(item).portion_name
if pkmn.egg?
scene.pbDisplay(_INTL("Eggs can't hold items."))
return false
elsif pkmn.mail
scene.pbDisplay(_INTL("{1}'s mail must be removed before giving it an item.", pkmn.name))
return false if !pbTakeItemFromPokemon(pkmn, scene)
end
if pkmn.hasItem?
olditemname = pkmn.item.portion_name
if olditemname.starts_with_vowel?
scene.pbDisplay(_INTL("{1} is already holding an {2}.", pkmn.name, olditemname) + "\1")
else
scene.pbDisplay(_INTL("{1} is already holding a {2}.", pkmn.name, olditemname) + "\1")
end
if scene.pbConfirm(_INTL("Would you like to switch the two items?"))
$bag.remove(item)
if !$bag.add(pkmn.item)
raise _INTL("Couldn't re-store deleted item in Bag somehow") if !$bag.add(item)
scene.pbDisplay(_INTL("The Bag is full. The Pokémon's item could not be removed."))
elsif GameData::Item.get(item).is_mail?
if pbWriteMail(item, pkmn, pkmnid, scene)
pkmn.item = item
scene.pbDisplay(_INTL("Took the {1} from {2} and gave it the {3}.", olditemname, pkmn.name, newitemname))
return true
elsif !$bag.add(item)
raise _INTL("Couldn't re-store deleted item in Bag somehow")
end
else
pkmn.item = item
scene.pbDisplay(_INTL("Took the {1} from {2} and gave it the {3}.", olditemname, pkmn.name, newitemname))
return true
end
end
elsif !GameData::Item.get(item).is_mail? || pbWriteMail(item, pkmn, pkmnid, scene)
$bag.remove(item)
pkmn.item = item
scene.pbDisplay(_INTL("{1} is now holding the {2}.", pkmn.name, newitemname))
return true
end
return false
end
# TODO: Replace all pbDisplay and so on in here.
def pbTakeItemFromPokemon(pkmn, scene)
ret = false
if !pkmn.hasItem?
scene.pbDisplay(_INTL("{1} isn't holding anything.", pkmn.name))
elsif !$bag.can_add?(pkmn.item)
scene.pbDisplay(_INTL("The Bag is full. The Pokémon's item could not be removed."))
elsif pkmn.mail
if scene.pbConfirm(_INTL("Save the removed mail in your PC?"))
if pbMoveToMailbox(pkmn)
pkmn.item = nil
scene.pbDisplay(_INTL("The mail was saved in your PC."))
ret = true
else
scene.pbDisplay(_INTL("Your PC's Mailbox is full."))
end
elsif scene.pbConfirm(_INTL("If the mail is removed, its message will be lost. OK?"))
item_name = pkmn.item.portion_name
$bag.add(pkmn.item)
pkmn.item = nil
scene.pbDisplay(_INTL("Received the {1} from {2}.", item_name, pkmn.name))
ret = true
end
else
item_name = pkmn.item.portion_name
$bag.add(pkmn.item)
pkmn.item = nil
scene.pbDisplay(_INTL("Received the {1} from {2}.", item_name, pkmn.name))
ret = true
end
return ret
end
#===============================================================================
# Choose an item from a given list. Only lets you choose an item you have at
# least 1 of in the Bag. The chosen item's ID is stored in the given Game
# Variable.
#===============================================================================
def pbChooseItemFromList(message, variable, *args)
commands = {}
args.each do |item|
item_data = GameData::Item.try_get(item)
next if !item_data || !$bag.has?(item_data.id)
commands[item_data.id] = item_data.name
end
if commands.length == 0
$game_variables[variable] = :NONE
return nil
end
commands[:NONE] = _INTL("Cancel")
ret = pbMessage(message, commands.values, -1)
if ret < 0 || ret >= commands.length - 1
$game_variables[variable] = :NONE
return nil
end
$game_variables[variable] = commands.keys[ret] || :NONE
return commands.keys[ret]
end
#===============================================================================
# Change a Pokémon's level.
#===============================================================================
@@ -218,23 +499,9 @@ def pbChangeLevel(pkmn, new_level, scene)
end
end
def pbTopRightWindow(text, scene = nil)
window = Window_AdvancedTextPokemon.new(text)
window.width = 198
window.x = Graphics.width - window.width
window.y = 0
window.z = 99999
pbPlayDecisionSE
loop do
Graphics.update
Input.update
window.update
scene&.pbUpdate
break if Input.trigger?(Input::USE)
end
window.dispose
end
#===============================================================================
# Change a Pokémon's Experience amount.
#===============================================================================
def pbChangeExp(pkmn, new_exp, scene)
new_exp = new_exp.clamp(0, pkmn.growth_rate.maximum_exp)
if pkmn.exp == new_exp
@@ -631,9 +898,6 @@ def pbLearnMove(pkmn, move, ignore_if_known = false, by_machine = false, screen
if by_machine && Settings::TAUGHT_MACHINES_KEEP_OLD_PP
pkmn.moves[move_index].pp = [old_move_pp, pkmn.moves[move_index].total_pp].min
end
# TODO: The last \\wt[16] is skipped in instant text speed. Or rather,
# the text after it is shown at the same time as the text before
# it, but the SE waits for that duration and then plays.
pbMessage(_INTL("1, 2, and...\\wt[16] ...\\wt[16] ...\\wt[16] Ta-da!") + "\\se[Battle ball drop]\1", &block)
pbMessage(_INTL("{1} forgot how to use {2}.\nAnd...", pkmn_name, old_move_name) + "\1", &block)
pbMessage("\\se[]" + _INTL("{1} learned {2}!", pkmn_name, move_name) + "\\se[Pkmn move learnt]", &block)
@@ -658,296 +922,3 @@ def pbForgetMove(pkmn, move_to_learn, screen = nil)
end
return ret
end
#===============================================================================
# Use an item from the Bag and/or on a Pokémon.
#===============================================================================
# Called from the Bag screen and also when prompted to use a Repel when one runs
# out (bag_scene will be nil for the latter).
# @return [Integer] 0 = item wasn't used; 1 = item used; 2 = close Bag to use in field
def pbUseItem(bag, item, bag_scene = nil)
itm = GameData::Item.get(item)
useType = itm.field_use
if useType == 1 # Item is usable on a Pokémon
if $player.pokemon_count == 0
pbMessage(_INTL("There is no Pokémon."))
return 0
end
ret = false
annot = nil
if itm.is_evolution_stone?
annot = []
$player.party.each do |pkmn|
elig = pkmn.check_evolution_on_use_item(item)
annot.push((elig) ? _INTL("ABLE") : _INTL("NOT ABLE"))
end
end
pbFadeOutIn do
screen = UI::Party.new($player.party, mode: :use_item)
if itm.is_evolution_stone?
screen.set_able_annotation_proc(proc { |pkmn| next pkmn.check_evolution_on_use_item(item) })
end
screen.choose_pokemon do |pkmn, party_index|
next true if party_index < 0
next false if !pbCheckUseOnPokemon(item, pkmn)
qty = 1
max_at_once = ItemHandlers.triggerUseOnPokemonMaximum(item, pkmn)
max_at_once = [max_at_once, bag.quantity(item)].min
if max_at_once > 1
pbPlayDecisionSE
qty = screen.choose_number(
_INTL("How many {1} do you want to use?", GameData::Item.get(item).portion_name_plural), max_at_once
)
screen.set_help_text("")
end
next false if qty <= 0
ret = ItemHandlers.triggerUseOnPokemon(item, qty, pkmn, screen)
if ret && itm.consumed_after_use?
bag.remove(item, qty)
if !bag.has?(item)
screen.show_message(_INTL("You used your last {1}.", itm.portion_name))
next true
end
end
next false
end
bag_scene&.pbRefresh
end
return (ret) ? 1 : 0
elsif useType == 2 || itm.is_machine? # Item is usable from Bag or teaches a move
intret = ItemHandlers.triggerUseFromBag(item, bag_scene)
if intret >= 0
bag.remove(item) if intret == 1 && itm.consumed_after_use?
return intret
end
pbMessage(_INTL("Can't use that here."))
return 0
end
pbMessage(_INTL("Can't use that here."))
return 0
end
# Only called when in the party screen and having chosen an item to be used on
# the selected Pokémon.
# TODO: Replace all pbMessage and so on in here. scene is the party screen.
def pbUseItemOnPokemon(item, pkmn, scene)
itm = GameData::Item.get(item)
# TM or HM
if itm.is_machine?
machine = itm.move
return false if !machine
movename = GameData::Move.get(machine).name
if pkmn.shadowPokemon?
pbMessage(_INTL("Shadow Pokémon can't be taught any moves.")) { scene.pbUpdate }
elsif !pkmn.compatible_with_move?(machine)
pbMessage(_INTL("{1} can't learn {2}.", pkmn.name, movename)) { scene.pbUpdate }
else
pbMessage("\\se[PC access]" + _INTL("You booted up the {1}.", itm.portion_name) + "\1") { scene.pbUpdate }
if pbConfirmMessage(_INTL("Do you want to teach {1} to {2}?", movename, pkmn.name)) { scene.pbUpdate }
if pbLearnMove(pkmn, machine, false, true) { scene.pbUpdate }
$bag.remove(item) if itm.consumed_after_use?
return true
end
end
end
return false
end
# Other item
qty = 1
max_at_once = ItemHandlers.triggerUseOnPokemonMaximum(item, pkmn)
max_at_once = [max_at_once, $bag.quantity(item)].min
if max_at_once > 1
qty = scene.scene.pbChooseNumber(
_INTL("How many {1} do you want to use?", itm.portion_name_plural), max_at_once
)
scene.set_help_text("") if scene.is_a?(UI::Party)
end
return false if qty <= 0
ret = ItemHandlers.triggerUseOnPokemon(item, qty, pkmn, scene)
scene.clear_annotations
scene.refresh
if ret && itm.consumed_after_use?
$bag.remove(item, qty)
if !$bag.has?(item)
pbMessage(_INTL("You used your last {1}.", itm.portion_name)) { scene.pbUpdate }
end
end
return ret
end
def pbUseKeyItemInField(item)
ret = ItemHandlers.triggerUseInField(item)
if ret == -1 # Item effect not found
pbMessage(_INTL("Can't use that here."))
elsif ret > 0 && GameData::Item.get(item).consumed_after_use?
$bag.remove(item)
end
return ret > 0
end
def pbUseItemMessage(item)
itemname = GameData::Item.get(item).portion_name
if itemname.starts_with_vowel?
pbMessage(_INTL("You used an {1}.", itemname))
else
pbMessage(_INTL("You used a {1}.", itemname))
end
end
# Returns whether pkmn is able to have an item used on it.
def pbCheckUseOnPokemon(item, pkmn)
return pkmn && !pkmn.egg? && (!pkmn.hyper_mode || GameData::Item.get(item)&.is_scent?)
end
# This method assumes the item is usable on a Pokémon. It returns whether the
# item will have an effect when used on pkmn.
def pbItemHasEffectOnPokemon?(item, pkmn)
return false if !pbCheckUseOnPokemon(item, pkmn)
ret = ItemHandlers.triggerUsableOnPokemon(item, pkmn)
return ret
end
#===============================================================================
# Give an item to a Pokémon to hold, and take a held item from a Pokémon.
#===============================================================================
# TODO: Replace all pbDisplay and so on in here.
def pbGiveItemToPokemon(item, pkmn, scene, pkmnid = 0)
return false if item.nil?
newitemname = GameData::Item.get(item).portion_name
if pkmn.egg?
scene.pbDisplay(_INTL("Eggs can't hold items."))
return false
elsif pkmn.mail
scene.pbDisplay(_INTL("{1}'s mail must be removed before giving it an item.", pkmn.name))
return false if !pbTakeItemFromPokemon(pkmn, scene)
end
if pkmn.hasItem?
olditemname = pkmn.item.portion_name
if olditemname.starts_with_vowel?
scene.pbDisplay(_INTL("{1} is already holding an {2}.", pkmn.name, olditemname) + "\1")
else
scene.pbDisplay(_INTL("{1} is already holding a {2}.", pkmn.name, olditemname) + "\1")
end
if scene.pbConfirm(_INTL("Would you like to switch the two items?"))
$bag.remove(item)
if !$bag.add(pkmn.item)
raise _INTL("Couldn't re-store deleted item in Bag somehow") if !$bag.add(item)
scene.pbDisplay(_INTL("The Bag is full. The Pokémon's item could not be removed."))
elsif GameData::Item.get(item).is_mail?
if pbWriteMail(item, pkmn, pkmnid, scene)
pkmn.item = item
scene.pbDisplay(_INTL("Took the {1} from {2} and gave it the {3}.", olditemname, pkmn.name, newitemname))
return true
elsif !$bag.add(item)
raise _INTL("Couldn't re-store deleted item in Bag somehow")
end
else
pkmn.item = item
scene.pbDisplay(_INTL("Took the {1} from {2} and gave it the {3}.", olditemname, pkmn.name, newitemname))
return true
end
end
elsif !GameData::Item.get(item).is_mail? || pbWriteMail(item, pkmn, pkmnid, scene)
$bag.remove(item)
pkmn.item = item
scene.pbDisplay(_INTL("{1} is now holding the {2}.", pkmn.name, newitemname))
return true
end
return false
end
# TODO: Replace all pbDisplay and so on in here.
def pbTakeItemFromPokemon(pkmn, scene)
ret = false
if !pkmn.hasItem?
scene.pbDisplay(_INTL("{1} isn't holding anything.", pkmn.name))
elsif !$bag.can_add?(pkmn.item)
scene.pbDisplay(_INTL("The Bag is full. The Pokémon's item could not be removed."))
elsif pkmn.mail
if scene.pbConfirm(_INTL("Save the removed mail in your PC?"))
if pbMoveToMailbox(pkmn)
pkmn.item = nil
scene.pbDisplay(_INTL("The mail was saved in your PC."))
ret = true
else
scene.pbDisplay(_INTL("Your PC's Mailbox is full."))
end
elsif scene.pbConfirm(_INTL("If the mail is removed, its message will be lost. OK?"))
item_name = pkmn.item.portion_name
$bag.add(pkmn.item)
pkmn.item = nil
pkmn.mail = nil
scene.pbDisplay(_INTL("Received the {1} from {2}.", item_name, pkmn.name))
ret = true
end
else
item_name = pkmn.item.portion_name
$bag.add(pkmn.item)
pkmn.item = nil
scene.pbDisplay(_INTL("Received the {1} from {2}.", item_name, pkmn.name))
ret = true
end
return ret
end
#===============================================================================
# Choose an item from the Bag.
#===============================================================================
def pbChooseItem(var = 0, *args)
ret = nil
pbFadeOutIn do
bag_screen = UI::Bag.new($bag, mode: :choose_item)
ret = bag_screen.choose_item
end
$game_variables[var] = ret || :NONE if var > 0
return ret
end
def pbChooseApricorn(var = 0)
ret = nil
pbFadeOutIn do
bag_screen = UI::Bag.new($bag, mode: :choose_item)
bag_screen.set_filter_proc(proc { |item| GameData::Item.get(item).is_apricorn? })
ret = bag_screen.choose_item
end
$game_variables[var] = ret || :NONE if var > 0
return ret
end
def pbChooseFossil(var = 0)
ret = nil
pbFadeOutIn do
bag_screen = UI::Bag.new($bag, mode: :choose_item)
bag_screen.set_filter_proc(proc { |item| GameData::Item.get(item).is_fossil? })
ret = bag_screen.choose_item
end
$game_variables[var] = ret || :NONE if var > 0
return ret
end
# Shows a list of items to choose from, with the chosen item's ID being stored
# in the given Game Variable. Only items which the player has are listed.
def pbChooseItemFromList(message, variable, *args)
commands = []
itemid = []
args.each do |item|
next if !GameData::Item.exists?(item)
itm = GameData::Item.get(item)
next if !$bag.has?(itm)
commands.push(itm.name)
itemid.push(itm.id)
end
if commands.length == 0
$game_variables[variable] = :NONE
return nil
end
commands.push(_INTL("Cancel"))
itemid.push(nil)
ret = pbMessage(message, commands, -1)
if ret < 0 || ret >= commands.length - 1
$game_variables[variable] = :NONE
return nil
end
$game_variables[variable] = itemid[ret] || :NONE
return itemid[ret]
end