From 95ef337de8d3713f547b1366cfda4062438f00e6 Mon Sep 17 00:00:00 2001 From: chardub Date: Thu, 24 Apr 2025 19:46:52 -0400 Subject: [PATCH] Migrate a reorganizes bunch of files from PIF --- Data/Scripts.rxdata | Bin 594 -> 873 bytes Data/Scripts/001_Settings.rb | 70 +- .../01_Migration/020_UI_PokeMart.rb | 794 ++ .../01_Migration/MessageConfig.rb | 4 + .../Constants/Animation_constants.rb | 6 + .../998_InfiniteFusion/Constants/Constants.rb | 31 + .../Constants/KantoOutdoorMaps.rb | 93 + .../Constants/Switches_constants.rb | 172 + .../Constants/Variables_constants.rb | 131 + .../998_InfiniteFusion/Fusion/Fusing.rb | 323 + .../Fusion/Fusion data/FusedSpecies.rb | 403 + .../Fusion data/fused_species_integration.rb | 31 + .../998_InfiniteFusion/Fusion/fusion_utils.rb | 410 + .../Gameplay/PokeMart/ClothesMart.rb | 29 + .../Gameplay/PokeMart/ExclusiveItems.rb | 53 + .../Gameplay/PokeMart/PokemartMapTransfers.rb | 87 + .../Gameplay/Utils/EventUtils.rb | 38 + .../Gameplay/Utils/FusionUtils.rb | 6 + .../Gameplay/Utils/GameplayUtils.rb | 563 ++ .../Gameplay/Utils/GraphicsUtils.rb | 49 + .../Gameplay/Utils/MenuUtils.rb | 167 + .../Gameplay/Utils/OutfitUtils.rb | 56 + .../Gameplay/Utils/PlayerUtils.rb | 8 + .../Gameplay/Utils/PokemonUtils.rb | 247 + .../Gameplay/Utils/RepairUtils.rb | 102 + .../Gameplay/Utils/SpritesUtils.rb | 7 + .../Gameplay/Utils/SystemUtils.rb | 145 + .../998_InfiniteFusion/Gameplay/game_start.rb | 34 + .../InfiniteFusionSettings.rb | 672 ++ .../998_InfiniteFusion/Items/New Balls.rb | 128 + .../998_InfiniteFusion/Items/New HMs.rb | 141 + .../Items/New Items effects.rb | 1511 ++++ .../Outfits/001_OutfitsMain/LayeredClothes.rb | 409 + .../Outfits/001_OutfitsMain/OutfitSelector.rb | 174 + .../Outfits/001_OutfitsMain/OutfitsGlobal.rb | 75 + .../Outfits/001_OutfitsMain/OutfitsSearch.rb | 221 + .../998_InfiniteFusion/Outfits/ItemSets.rb | 185 + .../998_InfiniteFusion/Outfits/OutfitIds.rb | 148 + .../Outfits/UI/CharacterSelectMenu.rb | 181 + .../UI/CharacterSelectMenuPresenter.rb | 275 + .../Outfits/UI/LayeredClothes_Menus.rb | 265 + .../Outfits/UI/PokemonHatScreenPresenter.rb | 103 + .../Outfits/UI/PokemonHatScreenView.rb | 139 + .../Outfits/UI/TrainerClothesPreview.rb | 72 + .../UI/clothesShop/0_OutfitsMartAdapter.rb | 159 + .../UI/clothesShop/ClothesMartAdapter.rb | 116 + .../Outfits/UI/clothesShop/ClothesShop.rb | 146 + .../UI/clothesShop/ClothesShopPresenter.rb | 163 + .../ClothesShopPresenter_HatsMenu.rb | 154 + .../Outfits/UI/clothesShop/ClothesShopView.rb | 205 + .../Outfits/UI/clothesShop/HairMartAdapter.rb | 209 + .../UI/clothesShop/HairShopPresenter.rb | 68 + .../Outfits/UI/clothesShop/HatShopView.rb | 110 + .../Outfits/UI/clothesShop/HatsMartAdapter.rb | 230 + .../UI/hairMenu/HairStyleSelectionMenuView.rb | 160 + .../HairstyleSelectionMenuPresenter.rb | 187 + .../Outfits/utils/OutfitFilenameUtils.rb | 126 + .../Outfits/utils/OutfitsGameplayUtils.rb | 412 + .../Outfits/wrappers/001_Outfit.rb | 19 + .../Outfits/wrappers/Clothes.rb | 11 + .../Outfits/wrappers/Hairstyle.rb | 12 + .../Outfits/wrappers/Hat.rb | 11 + .../998_InfiniteFusion/Player/PlayerAddons.rb | 291 + .../Quests/01_quest_reward.rb | 15 + .../Quests/02_QuestRewards.rb | 15 + .../Randomizer/RandomizerUtils.rb | 111 + .../Showdown/ShowdownUtils.rb | 88 + Data/messages_core.dat | Bin 1060098 -> 1060346 bytes PBS/Gen 5 backup/items.txt | 5388 ++++++------ PBS/Gen 5 backup/pokemon.txt | 624 +- PBS/Gen 5 backup/pokemon_forms.txt | 2 +- PBS/Gen 6 backup/items.txt | 6564 ++++++++------- PBS/Gen 6 backup/pokemon.txt | 693 +- PBS/Gen 6 backup/pokemon_forms.txt | 6 +- PBS/Gen 7 backup/items.txt | 6450 +++++++------- PBS/Gen 7 backup/pokemon.txt | 758 +- PBS/Gen 7 backup/pokemon_forms.txt | 48 +- PBS/Gen 8 backup/items.txt | 7219 ++++++++-------- PBS/Gen 8 backup/moves.txt | 301 +- PBS/Gen 8 backup/pokemon.txt | 1031 +-- PBS/Gen 8 backup/pokemon_forms.txt | 369 +- PBS/abilities.txt | 172 - PBS/encounters.txt | 312 +- PBS/items.txt | 7487 ++++++++--------- PBS/map_connections.txt | 52 +- PBS/moves.txt | 1173 +-- PBS/pokemon.txt | 6135 ++++---------- PBS/pokemon_forms.txt | 2763 +----- PBS/town_map.txt | 71 +- PBS/trainer_types.txt | 19 - 90 files changed, 31218 insertions(+), 28195 deletions(-) create mode 100644 Data/Scripts/998_InfiniteFusion/01_Migration/020_UI_PokeMart.rb create mode 100644 Data/Scripts/998_InfiniteFusion/01_Migration/MessageConfig.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Constants/Animation_constants.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Constants/Constants.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Constants/KantoOutdoorMaps.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Constants/Switches_constants.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Constants/Variables_constants.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Fusion/Fusing.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/FusedSpecies.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/fused_species_integration.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Fusion/fusion_utils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ClothesMart.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ExclusiveItems.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/PokemartMapTransfers.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/EventUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/FusionUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GameplayUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GraphicsUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/MenuUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/OutfitUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PlayerUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PokemonUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/RepairUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SpritesUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SystemUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Gameplay/game_start.rb create mode 100644 Data/Scripts/998_InfiniteFusion/InfiniteFusionSettings.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Items/New Balls.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Items/New HMs.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Items/New Items effects.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/LayeredClothes.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitSelector.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsGlobal.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsSearch.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/ItemSets.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/OutfitIds.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenu.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenuPresenter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/LayeredClothes_Menus.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenPresenter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenView.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/TrainerClothesPreview.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/0_OutfitsMartAdapter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesMartAdapter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShop.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter_HatsMenu.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopView.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairMartAdapter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairShopPresenter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatShopView.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatsMartAdapter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairStyleSelectionMenuView.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairstyleSelectionMenuPresenter.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitFilenameUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitsGameplayUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/wrappers/001_Outfit.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Clothes.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hairstyle.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hat.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Player/PlayerAddons.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Quests/01_quest_reward.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Quests/02_QuestRewards.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Randomizer/RandomizerUtils.rb create mode 100644 Data/Scripts/998_InfiniteFusion/Showdown/ShowdownUtils.rb diff --git a/Data/Scripts.rxdata b/Data/Scripts.rxdata index d5b92295ef875261c39876fbfe26c5b6143a8cd9..4b19482cfb806bad7fc5f565999711745127bcd8 100644 GIT binary patch literal 873 zcmV-v1D5;*2wMkR2x$bALnH$t5l3NdWm9EzbZKs9b0SE1oXgEmDa}b$2u>|2$;?YH z=H*gQP;htjb&dCQQLt68@^p*$@OSm|Lx_jD1_gWi`vE1@4fPDvdAU;aQUJK*5>Q(R zX#_amvI8OsO<`$nA_DjVc$|GyOK;mS488}*e_-4Iw$VUs4?Ao?R}AYm^f0VwdP{;p zv1wbYDjAa8v}^j`N6B`aV2=cGOiKJnetew3eI+d98Z9X8V5`johyq-NQ1V9vIz*M3 zm)c=I8IQ)J9O=~X3^zP`SR1UhapMty7lR%yVLD-Zk!4aVJi5VA({%ZEmcnbaIC-63yshYY_ia93&p+SY+}_U@(+lSGTC5fqtGDRQBZP-R z*BIq}Kccm~L^y?Lsg^3Dm%;Z>EmT7KC>@Vb<$X$q3ybR^F*HUS4@+bWkj#o-2p=!u z{rUNM8~axwk?9&$67Q{<)MY$_cpFn1uq$>@u&ogelj$UFqlMNZ#P_|Cr`l-^8&NX& z(YU&CAQT*fdQ+4Z4rC~!+4m#|m` zIoz;&S(Hi}%)K15cowtpD24NXB1hhd?Y%hI_}{fKtRM~5xO10l&p{iq!e{3>?a-M} znQU^rN{Y0-kOV?=VK8&ryj%qgU&=FI$0AMPst=XbjjhNKK6KgiiajO0-cplJ2GPfM z6ji2k-?u|8kDbmSGErMfy0Hr=j55soT5hlus(mHTPh2J*aRy4r8T6SMv{{2N4`un% z_m}@Pb*QV<#tbe1)qCb;o4>4!0>D_&ESRGe)^p@8I#$||AC{oKw# zINwlGJfM7`_%hy5x4r0wddfO3B^h&|G>HkVfGg5x`jHf3Lx@jAuOPi1Rsmb8TZx=d zXi*@kxg&&k?72h92t%vj3@AJ)$b-|}m7LM%&>!pqeS%CIio>!%QDlr?)>GdB2$kdG^QlOOKrX zZHMf;v2V(*e}}g06hmVMMc1AGo#vrSgDyQ@2mdsUuDRo9EkV}rLjU~@Nd@D0wW^~; literal 594 zcmV-Y0JBO21Qg!A_6f2c$|GxO^=%}5WPpre;C+E zfHpFlV-IN$-L~qf)h0Jc5g$Y1F0qkqnr=h>du<3fblYBl`Fb<+=5Ytx1C>y4l)$)x z6Bo}wOHc=deR@RDL1ejjsTCH^d^VpIsG}myF-!C3L}1N@n$G}?+4*4&3x|v*$t%uq zl0h)d4`*mI)f&H!C?cE8@x%D+$HjdRU%~*+Zgh8EtS&qKeEPK6B%Ak7pTBN5(PBju zPv|aM?Jn-cAaoCbsu9feKBAQA9^oF`n8nQ1AGY^*PMNR$ZZMxAD~6RsN+l+CF%*Ie z1FOlfkVMj72yfT$=Ha0q{UfcA@EV!#jm4zmdv6Ke$QbVjE+I4mpm!thi1u3~Ohw6*8M9e0AV}?JKA*O`&8a(1b+YaBv>r-^Jqo$w& zbH&BWyAH?PBs2#pgFbI;P3lG-{4y|=P8o&YViNB99J}##@Y`IS8WWK%LONs{9>!On zFSSS=Ynrtt3+22py0yog&bkCwxcx14M%$qfO-?Z!Gs8V)!-)7Jt$c&H1V*dnxT-*z zHwc^VE*}PcSuNZI2*Z :LATIAS, - :level => 30, - :icon => "pin_latias", - :game_switch => 53, - :encounter_type => :all, - :bgm => "Battle roaming" - }, - { - :species => :LATIOS, - :level => 30, - :icon => "pin_latios", - :game_switch => 53, - :encounter_type => :all, - :bgm => "Battle roaming" - }, - { - :species => :KYOGRE, - :level => 40, - :game_switch => 54, - :encounter_type => :surfing, - :areas => { - 2 => [ 21, 31 ], - 21 => [2, 31, 69], - 31 => [2, 21, 69], - 69 => [ 21, 31 ] - } - }, - { - :species => :ENTEI, - :level => 40, - :icon => "pin_entei", - :game_switch => 55, - :encounter_type => :land - } + # { + # :species => :LATIAS, + # :level => 30, + # :icon => "pin_latias", + # :game_switch => 53, + # :encounter_type => :all, + # :bgm => "Battle roaming" + # }, + # { + # :species => :LATIOS, + # :level => 30, + # :icon => "pin_latios", + # :game_switch => 53, + # :encounter_type => :all, + # :bgm => "Battle roaming" + # }, + # { + # :species => :KYOGRE, + # :level => 40, + # :game_switch => 54, + # :encounter_type => :surfing, + # :areas => { + # 2 => [ 21, 31 ], + # 21 => [2, 31, 69], + # 31 => [2, 21, 69], + # 69 => [ 21, 31 ] + # } + # }, + # { + # :species => :ENTEI, + # :level => 40, + # :icon => "pin_entei", + # :game_switch => 55, + # :encounter_type => :land + # } ] #----------------------------------------------------------------------------- diff --git a/Data/Scripts/998_InfiniteFusion/01_Migration/020_UI_PokeMart.rb b/Data/Scripts/998_InfiniteFusion/01_Migration/020_UI_PokeMart.rb new file mode 100644 index 000000000..ca146f723 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/01_Migration/020_UI_PokeMart.rb @@ -0,0 +1,794 @@ +#=============================================================================== +# Abstraction layer for Pokemon Essentials +#=============================================================================== +class PokemonMartAdapter + def getMoney + return $Trainer.money + end + + def getMoneyString + return pbGetGoldString + end + + def setMoney(value) + $Trainer.money = value + end + + def getInventory + return $PokemonBag + end + + def getName(item) + return GameData::Item.get(item).name + end + + def getDisplayName(item) + item_name = getName(item) + if GameData::Item.get(item).is_machine? + machine = GameData::Item.get(item).move + item_name = _INTL("{1} {2}", item_name, GameData::Move.get(machine).name) + end + return item_name + end + + def getDescription(item) + return GameData::Item.get(item).description + end + + def getItemIcon(item) + return (item) ? GameData::Item.icon_filename(item) : nil + end + + # Unused + def getItemIconRect(_item) + return Rect.new(0, 0, 48, 48) + end + + def getQuantity(item) + return $PokemonBag.pbQuantity(item) + end + + def showQuantity?(item) + return !GameData::Item.get(item).is_important? + end + + def getPrice(item, selling = false) + if $game_temp.mart_prices && $game_temp.mart_prices[item] + if selling + return $game_temp.mart_prices[item][1] if $game_temp.mart_prices[item][1] >= 0 + else + return $game_temp.mart_prices[item][0] if $game_temp.mart_prices[item][0] > 0 + end + end + return GameData::Item.get(item).price + end + + def getDisplayPrice(item, selling = false) + price = getPrice(item, selling).to_s_formatted + return _INTL("$ {1}", price) + end + + def canSell?(item) + return getPrice(item, true) > 0 && !GameData::Item.get(item).is_important? + end + + def addItem(item) + return $PokemonBag.pbStoreItem(item) + end + + def removeItem(item) + return $PokemonBag.pbDeleteItem(item) + end + + def getBaseColorOverride(item) + return nil + end + + def getShadowColorOverride(item) + return nil + end + + #specialType is a symbol + def getSpecialItemCaption(specialType) + return nil + end + + def getSpecialItemDescription(specialType) + return nil + end + + def doSpecialItemAction(specialType,itemId=nil) + return nil + end + + def getSpecialItemBaseColor(specialType) + return nil + end + + def getSpecialItemShadowColor(specialType) + return nil + end + + +end + +#=============================================================================== +# Buy and Sell adapters +#=============================================================================== +class BuyAdapter + def initialize(adapter) + @adapter = adapter + end + + def getDisplayName(item) + @adapter.getDisplayName(item) + end + + def getDisplayPrice(item) + @adapter.getDisplayPrice(item, false) + end + + def getBaseColorOverride(item) + return @adapter.getBaseColorOverride(item) + end + + def getShadowColorOverride(item) + return @adapter.getShadowColorOverride(item) + end + + def isSelling? + return false + end + + def getSpecialItemCaption(specialType) + return @adapter.getSpecialItemCaption(specialType) + end + + def getSpecialItemBaseColor(specialType) + return @adapter.getSpecialItemBaseColor(specialType) + end + + def getSpecialItemShadowColor(specialType) + return @adapter.getSpecialItemShadowColor(specialType) + end + + def getAdapter() + return @adapter + end +end + +#=============================================================================== +# +#=============================================================================== +class SellAdapter + def initialize(adapter) + @adapter = adapter + end + + def getDisplayName(item) + @adapter.getDisplayName(item) + end + + def getDisplayPrice(item) + if @adapter.showQuantity?(item) + return sprintf("x%d", @adapter.getQuantity(item)) + else + return "" + end + end + + def isSelling? + return true + end + + def getBaseColorOverride(item) + return @adapter.getBaseColorOverride(item) + end + + def getShadowColorOverride(item) + return @adapter.getShadowColorOverride(item) + end + +end + +#=============================================================================== +# Pokémon Mart +#=============================================================================== +class Window_PokemonMart < Window_DrawableCommand + def initialize(stock, adapter, x, y, width, height, viewport = nil) + @stock = stock + @adapter = adapter + super(x, y, width, height, viewport) + @selarrow = AnimatedBitmap.new("Graphics/Pictures/martSel") + @baseColor = Color.new(88, 88, 80) + @shadowColor = Color.new(168, 184, 184) + self.windowskin = nil + end + + def itemCount + return @stock.length + 1 + end + + def item + return (self.index >= @stock.length) ? nil : @stock[self.index] + end + + def drawItem(index, count, rect) + textpos = [] + rect = drawCursor(index, rect) + ypos = rect.y + if index == count - 1 + textpos.push([_INTL("CANCEL"), rect.x, ypos - 4, false, self.baseColor, self.shadowColor]) + else + item = @stock[index] + if item.is_a?(Symbol) && @adapter.getAdapter().is_a?(OutfitsMartAdapter) + itemname = @adapter.getSpecialItemCaption(item) + baseColor = @adapter.getSpecialItemBaseColor(item) ? @adapter.getSpecialItemBaseColor(item) : baseColor + shadowColor = @adapter.getSpecialItemShadowColor(item) ? @adapter.getSpecialItemShadowColor(item) : shadowColor + textpos.push([itemname, rect.x, ypos - 4, false, baseColor, shadowColor]) + else + itemname = @adapter.getDisplayName(item) + baseColorOverride = @adapter.getBaseColorOverride(item) + shadowColorOverride = @adapter.getShadowColorOverride(item) + + baseColor = baseColorOverride ? baseColorOverride : self.baseColor + shadowColor = shadowColorOverride ? shadowColorOverride : self.shadowColor + + qty = @adapter.getDisplayPrice(item) + sizeQty = self.contents.text_size(qty).width + xQty = rect.x + rect.width - sizeQty - 2 - 16 + textpos.push([itemname, rect.x, ypos - 4, false, baseColor, shadowColor]) + textpos.push([qty, xQty, ypos - 4, false, baseColor, shadowColor]) + end + end + pbDrawTextPositions(self.contents, textpos) + end +end + +#=============================================================================== +# +#=============================================================================== +class PokemonMart_Scene + def initialize(currency_name = "Money") + @currency_name = currency_name + end + + def update + pbUpdateSpriteHash(@sprites) + @subscene.pbUpdate if @subscene + end + + def pbRefresh + if @subscene + @subscene.pbRefresh + else + itemwindow = @sprites["itemwindow"] + @sprites["icon"].item = itemwindow.item + @sprites["itemtextwindow"].text = + (itemwindow.item) ? @adapter.getDescription(itemwindow.item) : _INTL("Quit shopping.") + itemwindow.refresh + end + @sprites["moneywindow"].text = _INTL("{2}:\r\n{1}", @adapter.getMoneyString, @currency_name) + end + + def scroll_map() + pbScrollMap(6, 5, 5) + end + + def scroll_back_map() + pbScrollMap(4, 5, 5) + end + + def pbStartBuyOrSellScene(buying, stock, adapter) + # Scroll right before showing screen + scroll_map() + @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height) + @viewport.z = 99999 + @stock = stock + @adapter = adapter + @sprites = {} + @sprites["background"] = IconSprite.new(0, 0, @viewport) + @sprites["background"].setBitmap("Graphics/Pictures/martScreen") + @sprites["icon"] = ItemIconSprite.new(36, Graphics.height - 50, nil, @viewport) + winAdapter = buying ? BuyAdapter.new(adapter) : SellAdapter.new(adapter) + @sprites["itemwindow"] = Window_PokemonMart.new(stock, winAdapter, + Graphics.width - 316 - 16, 12, 330 + 16, Graphics.height - 126) + @sprites["itemwindow"].viewport = @viewport + @sprites["itemwindow"].index = 0 + @sprites["itemwindow"].refresh + @sprites["itemtextwindow"] = Window_UnformattedTextPokemon.newWithSize("", + 64, Graphics.height - 96 - 16, Graphics.width - 64, 128, @viewport) + pbPrepareWindow(@sprites["itemtextwindow"]) + @sprites["itemtextwindow"].baseColor = Color.new(248, 248, 248) + @sprites["itemtextwindow"].shadowColor = Color.new(0, 0, 0) + @sprites["itemtextwindow"].windowskin = nil + @sprites["helpwindow"] = Window_AdvancedTextPokemon.new("") + pbPrepareWindow(@sprites["helpwindow"]) + @sprites["helpwindow"].visible = false + @sprites["helpwindow"].viewport = @viewport + pbBottomLeftLines(@sprites["helpwindow"], 1) + @sprites["moneywindow"] = Window_AdvancedTextPokemon.new("") + pbPrepareWindow(@sprites["moneywindow"]) + @sprites["moneywindow"].setSkin("Graphics/Windowskins/goldskin") + @sprites["moneywindow"].visible = true + @sprites["moneywindow"].viewport = @viewport + @sprites["moneywindow"].x = 0 + @sprites["moneywindow"].y = 0 + @sprites["moneywindow"].width = 190 + @sprites["moneywindow"].height = 96 + @sprites["moneywindow"].baseColor = Color.new(88, 88, 80) + @sprites["moneywindow"].shadowColor = Color.new(168, 184, 184) + pbDeactivateWindows(@sprites) + @buying = buying + pbRefresh + Graphics.frame_reset + end + + def pbStartBuyScene(stock, adapter) + pbStartBuyOrSellScene(true, stock, adapter) + end + + def pbStartSellScene(bag, adapter) + if $PokemonBag + pbStartSellScene2(bag, adapter) + else + pbStartBuyOrSellScene(false, bag, adapter) + end + end + + def pbStartSellScene2(bag, adapter) + @subscene = PokemonBag_Scene.new + @adapter = adapter + @viewport2 = Viewport.new(0, 0, Graphics.width, Graphics.height) + @viewport2.z = 99999 + numFrames = Graphics.frame_rate * 4 / 10 + alphaDiff = (255.0 / numFrames).ceil + for j in 0..numFrames + col = Color.new(0, 0, 0, j * alphaDiff) + @viewport2.color = col + Graphics.update + Input.update + end + @subscene.pbStartScene(bag) + @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height) + @viewport.z = 99999 + @sprites = {} + @sprites["helpwindow"] = Window_AdvancedTextPokemon.new("") + pbPrepareWindow(@sprites["helpwindow"]) + @sprites["helpwindow"].visible = false + @sprites["helpwindow"].viewport = @viewport + pbBottomLeftLines(@sprites["helpwindow"], 1) + @sprites["moneywindow"] = Window_AdvancedTextPokemon.new("") + pbPrepareWindow(@sprites["moneywindow"]) + @sprites["moneywindow"].setSkin("Graphics/Windowskins/goldskin") + @sprites["moneywindow"].visible = false + @sprites["moneywindow"].viewport = @viewport + @sprites["moneywindow"].x = 0 + @sprites["moneywindow"].y = 0 + @sprites["moneywindow"].width = 186 + @sprites["moneywindow"].height = 96 + @sprites["moneywindow"].baseColor = Color.new(88, 88, 80) + @sprites["moneywindow"].shadowColor = Color.new(168, 184, 184) + pbDeactivateWindows(@sprites) + @buying = false + pbRefresh + end + + def pbEndBuyScene + pbDisposeSpriteHash(@sprites) + Kernel.pbClearText() + @viewport.dispose + # Scroll left after showing screen + scroll_back_map() + end + + def pbEndSellScene + @subscene.pbEndScene if @subscene + pbDisposeSpriteHash(@sprites) + if @viewport2 + numFrames = Graphics.frame_rate * 4 / 10 + alphaDiff = (255.0 / numFrames).ceil + for j in 0..numFrames + col = Color.new(0, 0, 0, (numFrames - j) * alphaDiff) + @viewport2.color = col + Graphics.update + Input.update + end + @viewport2.dispose + end + @viewport.dispose + pbScrollMap(4, 5, 5) if !@subscene + end + + def pbPrepareWindow(window) + window.visible = true + window.letterbyletter = false + end + + def pbShowMoney + pbRefresh + @sprites["moneywindow"].visible = true + end + + def pbHideMoney + pbRefresh + @sprites["moneywindow"].visible = false + end + + def pbDisplay(msg, brief = false) + cw = @sprites["helpwindow"] + cw.letterbyletter = true + cw.text = msg + pbBottomLeftLines(cw, 2) + cw.visible = true + i = 0 + pbPlayDecisionSE + loop do + Graphics.update + Input.update + self.update + if !cw.busy? + return if brief + pbRefresh if i == 0 + end + if Input.trigger?(Input::USE) && cw.busy? + cw.resume + end + return if i >= Graphics.frame_rate * 3 / 2 + i += 1 if !cw.busy? + end + end + + def pbDisplayPaused(msg) + cw = @sprites["helpwindow"] + cw.letterbyletter = true + cw.text = msg + pbBottomLeftLines(cw, 2) + cw.visible = true + yielded = false + pbPlayDecisionSE + loop do + Graphics.update + Input.update + wasbusy = cw.busy? + self.update + if !cw.busy? && !yielded + yield if block_given? # For playing SE as soon as the message is all shown + yielded = true + end + pbRefresh if !cw.busy? && wasbusy + if Input.trigger?(Input::USE) && cw.resume && !cw.busy? + @sprites["helpwindow"].visible = false + return + end + end + end + + def pbConfirm(msg) + dw = @sprites["helpwindow"] + dw.letterbyletter = true + dw.text = msg + dw.visible = true + pbBottomLeftLines(dw, 2) + commands = [_INTL("Yes"), _INTL("No")] + cw = Window_CommandPokemon.new(commands) + cw.viewport = @viewport + pbBottomRight(cw) + cw.y -= dw.height + cw.index = 0 + pbPlayDecisionSE + loop do + cw.visible = !dw.busy? + Graphics.update + Input.update + cw.update + self.update + if Input.trigger?(Input::BACK) && dw.resume && !dw.busy? + cw.dispose + @sprites["helpwindow"].visible = false + return false + end + if Input.trigger?(Input::USE) && dw.resume && !dw.busy? + cw.dispose + @sprites["helpwindow"].visible = false + return (cw.index == 0) + end + end + end + + def pbChooseNumber(helptext, item, maximum) + curnumber = 1 + ret = 0 + helpwindow = @sprites["helpwindow"] + itemprice = @adapter.getPrice(item, !@buying) + itemprice /= 2 if !@buying + pbDisplay(helptext, true) + using(numwindow = Window_AdvancedTextPokemon.new("")) { # Showing number of items + qty = @adapter.getQuantity(item) + using(inbagwindow = Window_AdvancedTextPokemon.new("")) { # Showing quantity in bag + pbPrepareWindow(numwindow) + pbPrepareWindow(inbagwindow) + numwindow.viewport = @viewport + numwindow.width = 224 + numwindow.height = 64 + numwindow.baseColor = Color.new(88, 88, 80) + numwindow.shadowColor = Color.new(168, 184, 184) + inbagwindow.visible = @buying + inbagwindow.viewport = @viewport + inbagwindow.width = 190 + inbagwindow.height = 64 + inbagwindow.baseColor = Color.new(88, 88, 80) + inbagwindow.shadowColor = Color.new(168, 184, 184) + inbagwindow.text = _INTL("In Bag:{1} ", qty) + numwindow.text = _INTL("x{1}$ {2}", curnumber, (curnumber * itemprice).to_s_formatted) + pbBottomRight(numwindow) + numwindow.y -= helpwindow.height + pbBottomLeft(inbagwindow) + inbagwindow.y -= helpwindow.height + loop do + Graphics.update + Input.update + numwindow.update + inbagwindow.update + self.update + if Input.repeat?(Input::LEFT) + pbPlayCursorSE + curnumber -= 10 + curnumber = 1 if curnumber < 1 + numwindow.text = _INTL("x{1}$ {2}", curnumber, (curnumber * itemprice).to_s_formatted) + elsif Input.repeat?(Input::RIGHT) + pbPlayCursorSE + curnumber += 10 + curnumber = maximum if curnumber > maximum + numwindow.text = _INTL("x{1}$ {2}", curnumber, (curnumber * itemprice).to_s_formatted) + elsif Input.repeat?(Input::UP) + pbPlayCursorSE + curnumber += 1 + curnumber = 1 if curnumber > maximum + numwindow.text = _INTL("x{1}$ {2}", curnumber, (curnumber * itemprice).to_s_formatted) + elsif Input.repeat?(Input::DOWN) + pbPlayCursorSE + curnumber -= 1 + curnumber = maximum if curnumber < 1 + numwindow.text = _INTL("x{1}$ {2}", curnumber, (curnumber * itemprice).to_s_formatted) + elsif Input.trigger?(Input::USE) + pbPlayDecisionSE + ret = curnumber + break + elsif Input.trigger?(Input::BACK) + pbPlayCancelSE + ret = 0 + break + end + end + } + } + helpwindow.visible = false + return ret + end + + def pbChooseBuyItem + itemwindow = @sprites["itemwindow"] + @sprites["helpwindow"].visible = false + pbActivateWindow(@sprites, "itemwindow") { + pbRefresh + loop do + Graphics.update + Input.update + olditem = itemwindow.item + self.update + if itemwindow.item != olditem + @sprites["icon"].item = itemwindow.item + @sprites["itemtextwindow"].text = + (itemwindow.item) ? @adapter.getDescription(itemwindow.item) : _INTL("Quit shopping.") + end + if Input.trigger?(Input::BACK) + pbPlayCloseMenuSE + return nil + elsif Input.trigger?(Input::USE) + if itemwindow.index < @stock.length + pbRefresh + return @stock[itemwindow.index] + else + return nil + end + end + end + } + end + + def pbChooseSellItem + if @subscene + return @subscene.pbChooseItem + else + return pbChooseBuyItem + end + end +end + +#=============================================================================== +# +#=============================================================================== +class PokemonMartScreen + def initialize(scene, stock, adapter = PokemonMartAdapter.new) + @scene = scene + @stock = stock + @adapter = adapter + end + + def pbConfirm(msg) + return @scene.pbConfirm(msg) + end + + def pbDisplay(msg) + return @scene.pbDisplay(msg) + end + + def pbDisplayPaused(msg, &block) + return @scene.pbDisplayPaused(msg, &block) + end + + def pbBuyScreen + @scene.pbStartBuyScene(@stock, @adapter) + item = nil + loop do + pbWait(4) + item = @scene.pbChooseBuyItem + break if !item + quantity = 0 + itemname = @adapter.getDisplayName(item) + price = @adapter.getPrice(item) + if @adapter.getMoney < price + pbDisplayPaused(_INTL("You don't have enough money.")) + next + end + if GameData::Item.get(item).is_important? + if !pbConfirm(_INTL("Certainly. You want {1}. That will be ${2}. OK?", + itemname, price.to_s_formatted)) + next + end + quantity = 1 + else + maxafford = (price <= 0) ? Settings::BAG_MAX_PER_SLOT : @adapter.getMoney / price + maxafford = Settings::BAG_MAX_PER_SLOT if maxafford > Settings::BAG_MAX_PER_SLOT + quantity = @scene.pbChooseNumber( + _INTL("{1}? Certainly. How many would you like?", itemname), item, maxafford) + next if quantity == 0 + price *= quantity + if !pbConfirm(_INTL("{1}, and you want {2}. That will be ${3}. OK?", + itemname, quantity, price.to_s_formatted)) + next + end + end + if @adapter.getMoney < price + pbDisplayPaused(_INTL("You don't have enough money.")) + next + end + added = 0 + quantity.times do + break if !@adapter.addItem(item) + added += 1 + end + if added != quantity + added.times do + if !@adapter.removeItem(item) + raise _INTL("Failed to delete stored items") + end + end + pbDisplayPaused(_INTL("You have no more room in the Bag.")) + else + @adapter.setMoney(@adapter.getMoney - price) + for i in 0...@stock.length + if GameData::Item.get(@stock[i]).is_important? && $PokemonBag.pbHasItem?(@stock[i]) + @stock[i] = nil + end + end + @stock.compact! + pbDisplayPaused(_INTL("Here you are! Thank you!")) { pbSEPlay("Mart buy item") } + if $PokemonBag + if quantity >= 10 && GameData::Item.get(item).is_poke_ball? && GameData::Item.exists?(:PREMIERBALL) + if @adapter.addItem(GameData::Item.get(:PREMIERBALL)) + pbDisplayPaused(_INTL("I'll throw in a Premier Ball, too.")) + end + end + end + end + end + @scene.pbEndBuyScene + end + + def pbSellScreen + item = @scene.pbStartSellScene(@adapter.getInventory, @adapter) + loop do + item = @scene.pbChooseSellItem + break if !item + itemname = @adapter.getDisplayName(item) + price = @adapter.getPrice(item, true) + if !@adapter.canSell?(item) + pbDisplayPaused(_INTL("{1}? Oh, no. I can't buy that.", itemname)) + next + end + qty = @adapter.getQuantity(item) + next if qty == 0 + @scene.pbShowMoney + if qty > 1 + qty = @scene.pbChooseNumber( + _INTL("{1}? How many would you like to sell?", itemname), item, qty) + end + if qty == 0 + @scene.pbHideMoney + next + end + price /= 2 + price *= qty + if pbConfirm(_INTL("I can pay ${1}. Would that be OK?", price.to_s_formatted)) + @adapter.setMoney(@adapter.getMoney + price) + qty.times do + @adapter.removeItem(item) + end + pbDisplayPaused(_INTL("Turned over the {1} and received ${2}.", itemname, price.to_s_formatted)) { pbSEPlay("Mart buy item") } + @scene.pbRefresh + end + @scene.pbHideMoney + end + @scene.pbEndSellScene + end +end + +def replaceShopStockWithRandomized(stock) + if $PokemonGlobal.randomItemsHash != nil + newStock = [] + for item in stock + newItem = $PokemonGlobal.randomItemsHash[item] + if newItem != nil && GameData::Item.get(newItem).price > 0 && !Settings::EXCLUDE_FROM_RANDOM_SHOPS.include?(newItem) + newStock << newItem + else + newStock << item + end + end + return newStock + end + return stock +end + +#=============================================================================== +# +#=============================================================================== +def pbPokemonMart(stock, speech = nil, cantsell = false) + if $game_switches[SWITCH_RANDOM_ITEMS_GENERAL] && $game_switches[SWITCH_RANDOM_SHOP_ITEMS] + stock = replaceShopStockWithRandomized(stock) + end + + for i in 0...stock.length + stock[i] = GameData::Item.get(stock[i]).id + stock[i] = nil if GameData::Item.get(stock[i]).is_important? && $PokemonBag.pbHasItem?(stock[i]) + end + stock.compact! + commands = [] + cmdBuy = -1 + cmdSell = -1 + cmdQuit = -1 + commands[cmdBuy = commands.length] = _INTL("Buy") + commands[cmdSell = commands.length] = _INTL("Sell") if !cantsell + commands[cmdQuit = commands.length] = _INTL("Quit") + cmd = pbMessage( + speech ? speech : _INTL("Welcome! How may I serve you?"), + commands, cmdQuit + 1) + loop do + if cmdBuy >= 0 && cmd == cmdBuy + scene = PokemonMart_Scene.new + screen = PokemonMartScreen.new(scene, stock) + screen.pbBuyScreen + elsif cmdSell >= 0 && cmd == cmdSell + scene = PokemonMart_Scene.new + screen = PokemonMartScreen.new(scene, stock) + screen.pbSellScreen + else + pbMessage(_INTL("Please come again!")) + break + end + cmd = pbMessage(_INTL("Is there anything else I can help you with?"), + commands, cmdQuit + 1) + end + $game_temp.clear_mart_prices +end diff --git a/Data/Scripts/998_InfiniteFusion/01_Migration/MessageConfig.rb b/Data/Scripts/998_InfiniteFusion/01_Migration/MessageConfig.rb new file mode 100644 index 000000000..7dc0f649d --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/01_Migration/MessageConfig.rb @@ -0,0 +1,4 @@ +module MessageConfig + BLUE_TEXT_MAIN_COLOR = Color.new(35, 130, 200) + BLUE_TEXT_SHADOW_COLOR = Color.new(20, 75, 115) +end diff --git a/Data/Scripts/998_InfiniteFusion/Constants/Animation_constants.rb b/Data/Scripts/998_InfiniteFusion/Constants/Animation_constants.rb new file mode 100644 index 000000000..97d886393 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Constants/Animation_constants.rb @@ -0,0 +1,6 @@ +############## +# ANIMATIONS +################ +DUST_ANIMATION_ID=2 +VIRUS_ANIMATION_ID=10# frozen_string_literal: true + diff --git a/Data/Scripts/998_InfiniteFusion/Constants/Constants.rb b/Data/Scripts/998_InfiniteFusion/Constants/Constants.rb new file mode 100644 index 000000000..f5d3992d2 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Constants/Constants.rb @@ -0,0 +1,31 @@ +############# +# SETTINGS # +############# + + +# This is for settings that are used in scripts since it's a chore to change them everywhere to include the module name +NUM_BADGES = Settings::NB_BADGES +EGGINITIALLEVEL = Settings::EGG_LEVEL + +#this is fucking stupid but apparently necessary +FALSE = false +TRUE = true + +DIRECTION_LEFT = 4 +DIRECTION_RIGHT = 6 +DIRECTION_DOWN = 2 +DIRECTION_UP = 8 + +VAR_SPEED_UP_TOGGLE_SPEED=23 + +MAP_TEMPLATE_EVENTS = 175 +TEMPLATE_EVENT_SILHOUETTE = 7 + +SWITCH_TRIPLE_BOSS_BATTLE = 824 +SWITCH_SILVERBOSS_BATTLE = 675 + +GENDER_FEMALE=0 +GENDER_MALE=1 + +MELOETTA_BAND_NAME = "Miss Melody and the Mystic Musicians" +SUCKY_BAND_NAME = "MooMoo Milk" \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Constants/KantoOutdoorMaps.rb b/Data/Scripts/998_InfiniteFusion/Constants/KantoOutdoorMaps.rb new file mode 100644 index 000000000..7dd8900e5 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Constants/KantoOutdoorMaps.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + + +KANTO_OUTDOOR_MAPS = [ + 78, # Route 1 + 185, # Secret Garden + 86, # Route 2 + 90, # Route 2 (north) + 655, # Hidden Forest + 40, # Viridian River + 490, # Route 3 + 106, # Route 4 + 12, # Route 5 + 16, # Route 6 + 413, # Route 7 + 409, # Route 8 + 351, # Route 9 (east) + 495, # Route 9 (west) + 154, # Route 10 + 155, # Route 11 + 159, # Route 12 + 440, # Route 14 + 444, # Route 15 + 712, # Creepy house + 438, # Route 16 + 146, # Route 17 + 517, # Route 18 + 437, # Route 13 + 57, # Route 19 + 227, # Route 19 (underwater) + 56, # Route 19 (surf race) + 58, # Route 20 + 480, # Route 20 underwater 1 + 228, # Route 20 underwater 2 + 171, # Route 22 + 8, # Route 24 + 9, # Route 25 + 143, # Route 23 + 145, # Route 26 + 147, # Route 27 + 58, # Route 21 + # CITIES + 42, # Pallet Town + 79, # Viridian City + 1, # Cerulean City + 387, # Cerulean City (race) + 19, # Vermillion City + 36, # S.S. Anne deck + 95, # Celadon city + 436, # Celadon city dept store (roof) + 472, # Fuchsia city + 50, # Lavender town + 108, # Saffron city + 98, # Cinnabar island + 167, # Crimson city + 303, # indigo plateau + 380, # Pewter city + 827, # Mt. Moon summit + # + # DUNGEONS + # + 102, # Mt. Moon + 103, # Mt. Moon + 105, # Mt. Moon + 496, # Mt Moon + 104, # Mt. Moon + 494, # Mt. Moon Square + 140, # Diglett cave + 398, # Diglett cave + 399, # Diglett cave + 349, # Rock tunnel + 350, # Rock tunnel + 512, # Rock tunnel (outdoor) + 445, # Safari Zone 1 + 484, # Safari Zone 2 + 485, # Safari Zone 3 + 486, # Safari Zone 4 + 487, # Safari Zone 5 + 491, # Viridian Forest + 529, # Mt. Silver entrance + 777, # Mt. Silver outdoor 1 + 781, # Mt. Silver outdoor 2 + 782, # Mt. Silver + 783, # Mt. Silver summit + 400, # Pokemon Tower + 401, # Pokemon Tower + 402, # Pokemon Tower + 403, # Pokemon Tower + 467, # Pokemon Tower + 468, # Pokemon Tower + 469, # Pokemon Tower + +] \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Constants/Switches_constants.rb b/Data/Scripts/998_InfiniteFusion/Constants/Switches_constants.rb new file mode 100644 index 000000000..4e85aadc7 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Constants/Switches_constants.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +############# +# SWITCHES # +############# +#Game mode switches +SWITCH_NEW_GAME_PLUS = 972 +SWITCH_BEAT_MT_SILVER = 918 +BEAT_MT_SILVER = 918 #don't remove this - used in some events +SWITCH_REVERSED_MODE = 47 +SWITCH_GAME_DIFFICULTY_EASY = 665 +SWITCH_GAME_DIFFICULTY_HARD = 666 + +SWITCH_MODERN_MODE=974 +SWITCH_EXPERT_MODE=772 + +SWITCH_V5_1=825 +SWITCH_NO_LEVELS_MODE=774 +SWITCH_DOUBLE_ABILITIES=773 +SWITCH_SINGLE_SPECIES_MODE=790 +#Game progression switches +SWITCH_DURING_INTRO = 917 +SWITCH_CHOOSING_STARTER=3 +SWITCH_GOT_BADGE_1 = 4 +SWITCH_GOT_BADGE_2 = 5 +SWITCH_GOT_BADGE_3 = 6 +SWITCH_GOT_BADGE_4 = 7 +SWITCH_GOT_BADGE_5 = 8 +SWITCH_GOT_BADGE_6 = 9 +SWITCH_GOT_BADGE_7 = 10 +SWITCH_GOT_BADGE_8 = 11 +SWITCH_BEAT_THE_LEAGUE = 12 +SWITCH_GOT_BADGE_9 = 38 +SWITCH_GOT_BADGE_10 = 39 +SWITCH_GOT_BADGE_11 = 40 +SWITCH_GOT_BADGE_12 = 41 +SWITCH_GOT_BADGE_13 = 43 +SWITCH_GOT_BADGE_14 = 44 +SWITCH_GOT_BADGE_15 = 45 +SWITCH_GOT_BADGE_16 = 50 +SWITCH_KANTO_DARKNESS = 701 +SWITCH_KANTO_DARKNESS_STAGE_1 = 702 +SWITCH_KANTO_DARKNESS_STAGE_2 = 703 +SWITCH_KANTO_DARKNESS_STAGE_3 = 704 +SWITCH_KANTO_DARKNESS_STAGE_4 = 705 + +SWITCH_ORICORIO_QUEST_PINK = 672 +SWITCH_ORICORIO_QUEST_RED = 673 +SWITCH_ORICORIO_QUEST_BLUE = 674 +SWITCH_ORICORIO_QUEST_IN_PROGRESS = 680 + +SWITCH_PICKED_HELIC_FOSSIL= 65 +SWITCH_PICKED_DOME_FOSSIL= 66 + +SWITCH_PICKED_LILEEP_FOSSIL= 589 +SWITCH_PICKED_ANORITH_FOSSIL= 90 + +SWITCH_PICKED_ARMOR_FOSSIL= 616 +SWITCH_PICKED_SKULL_FOSSIL= 617 + +SWITCH_NIGHTMARE_EFFECT= 805 + +SWITCH_JOHTO_STARTERS=884 +SWITCH_HOENN_STARTERS=885 +SWITCH_SINNOH_STARTERS=886 +SWITCH_KALOS_STARTERS=888 + +SWITCH_CUSTOM_STARTERS=883 + +SWITCH_JOINED_TEAM_ROCKET=1037 +SWITCH_PINKAN_SIDE_ROCKET=1099 +SWITCH_PINKAN_SIDE_POLICE=1100 +SWITCH_LEAVING_PINKAN_ISLAND=1113 +SWITCH_BLOCK_PINKAN_WHISTLE=1111 +SWITCH_PINKAN_FINISHED=1119 + +VAR_ORICORIO_FLOWERS = 276 +#Randomizer Switches +SWITCH_RANDOM_WILD_TO_FUSION=953 +SWITCH_RANDOMIZED_AT_LEAST_ONCE = 855 +ENABLED_DEBUG_MODE_AT_LEAST_ONCE = 842 + +SWITCH_RANDOM_WILD = 778 +SWITCH_RANDOM_WILD_AREA = 777 + +SWITCH_RANDOM_TRAINERS = 987 +SWITCH_RANDOM_STARTERS = 954 +SWITCH_RANDOM_STARTER_FIRST_STAGE = 771 + +SWITCH_RANDOM_ITEMS_GENERAL=759 +SWITCH_RANDOM_ITEMS=751 +SWITCH_RANDOM_FOUND_ITEMS=755 +SWITCH_RANDOM_ITEMS_DYNAMIC = 958 +SWITCH_RANDOM_ITEMS_MAPPED = 752 + +SWITCH_RANDOM_TMS = 758 +SWITCH_RANDOM_GIVEN_ITEMS = 756 +SWITCH_RANDOM_GIVEN_TMS = 757 +SWITCH_RANDOM_SHOP_ITEMS = 754 + + +SWITCH_RANDOM_FOUND_TMS = 959 +SWITCH_WILD_RANDOM_GLOBAL=956 +SWITCH_RANDOM_STATIC_ENCOUNTERS=955 +SWITCH_RANDOM_WILD_ONLY_CUSTOMS=664 +SWITCH_RANDOM_GYM_PERSIST_TEAMS=663 +SWITCH_GYM_RANDOM_EACH_BATTLE = 668 +SWITCH_RANDOM_GYM_CUSTOMS=662 +SWITCH_RANDOMIZE_GYMS_SEPARATELY = 667 +SWITCH_RANDOMIZED_GYM_TYPES=921 +SWITCH_RANDOM_GIFT_POKEMON = 780 +SWITCH_RANDOM_HELD_ITEMS = 843 +SWITCH_DEFINED_RIVAL_STARTER=840 +SWITCH_RANDOMIZED_WILD_POKEMON_TO_FUSIONS=829 + +SWITCH_RANDOM_WILD_LEGENDARIES=1031 +SWITCH_RANDOM_TRAINER_LEGENDARIES=1032 +SWITCH_RANDOM_GYM_LEGENDARIES=1033 +SWITCH_DONT_RANDOMIZE=890 + +#Other switches +SWITCH_RACE_BIKE = 984 +SWITCH_IS_REMATCH=200 +SWITCH_SINGLE_POKEMON_MODE=790 +SWITCH_SINGLE_POKEMON_MODE_HEAD=791 +SWITCH_SINGLE_POKEMON_MODE_BODY=792 +SWITCH_SINGLE_POKEMON_MODE_RANDOM=793 +SWITCH_FISHING_AUTOHOOK = 916 +SWITCH_FUSED_WILD_POKEMON=35 +SWITCH_FORCE_FUSE_NEXT_POKEMON=37 +SWITCH_FORCE_ALL_WILD_FUSIONS=828 +SWITCH_USED_AN_INCENSE=798 +SWITCH_FIRST_RIVAL_BATTLE=46 +SWITCH_BATTLE_FACTORY_INCLUDE_ALL = 775 +SWITCH_SUPER_SLOW_SPEED=649 +SWITCH_LOUNGE_BATTLE_LEVEL = 240 +SWITCH_CANNOT_CATCH_POKEMON = 75 +SWITCH_UNLOCKED_POKEMON_HATS = 770 +SWITCH_ILEX_FOREST_SPOOKED_POKEMON = 1021 + +SWITCH_LOCK_PLAYER_MOVEMENT = 815 +SWITCH_TEAMED_WITH_ERIKA_SEWERS=141 +SWITCH_BAND_DRUMMER = 1004 +SWITCH_BAND_ACOUSTIC_GUITAR = 1005 +SWITCH_BAND_ELECTRIC_GUITAR = 1006 +SWITCH_BAND_HARP = 1007 +SWITCH_BAND_FLUTE = 1008 + +SWITCH_SELECTING_CLOTHES = 804 + +SWITCH_KANTO_HAIR_COLLECTION = 1059 +SWITCH_JOHTO_HAIR_COLLECTION = 1060 +SWITCH_HOENN_HAIR_COLLECTION = 1061 +SWITCH_SINNOH_HAIR_COLLECTION = 1062 +SWITCH_UNOVA_HAIR_COLLECTION = 1063 +SWITCH_KALOS_HAIR_COLLECTION = 1064 +SWITCH_ALOLA_HAIR_COLLECTION = 1065 +SWITCH_GALAR_HAIR_COLLECTION = 1066 +SWITCH_PALDEA_HAIR_COLLECTION = 1067 +SWITCH_GEN10_HAIR_COLLECTION = 1068 + +SWITCH_SS_ANNE_DEPARTED = 88 +SWITCH_SNORLAX_GONE_ROUTE_12 = 110 +SWITCH_TELEPORT_NPC = 122 +SWITCH_GOT_DIVE = 317 +SWITCH_GOT_ROCK_CLIMB = 661 +SWITCH_GOT_WATERFALL = 388 + +SWITCH_UPDATED_TO_SPRITESHEETS_SPRITES=1117 +#OUTFITS +# +WEARING_ROCKET_OUTFIT = 1038 \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Constants/Variables_constants.rb b/Data/Scripts/998_InfiniteFusion/Constants/Variables_constants.rb new file mode 100644 index 000000000..c7fbfe168 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Constants/Variables_constants.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +############# +# VARIABLES # +############# +VAR_CURRENT_MART=291 +VAR_CURRENT_CITY_NUMERICAL_ID=14 #for wondertrade/pokemarts + + +VAR_SINGLE_POKEMON_MODE=251 +SINGLE_POKEMON_MODE_VAR=251 #c'est appellé comme ca en qqpart dans un event pis ca me tente pas de chercher ou + +VAR_WILD_FUSION_RATE=210 +VAR_ODDKEYSTONE_NB=252 +VAR_DEFAULT_BATTLE_TYPE = 242 +VAR_BATTLE_FACTORY_TOKENS = 243 +VAR_NB_GYM_REMATCHES = 162 +VAR_CUSTOM_SPRITES_ENABLED= 196 +VAR_COMMAND_WINDOW_INDEX=249 +VAR_STANDARD_WONDERTRADE_LEFT=248 +VAR_PREMIUM_WONDERTRADE_LEFT=111 +VAR_PREMIUM_WONDERTRADE_LEFT=111 +VAR_RIVAL_STARTER=250 +VAR_FUSION_ICON_STYLE=220 +VAR_SHINY_HUE_OFFSET=275 +VAR_CURRENT_HIDDEN_MAP = 226 +VAR_FUSE_COUNTER = 126 + +VAR_STAT_RARE_CANDY=265 +VAR_STAT_LEADER_REMATCH=162 +VAR_STAT_NB_FUSIONS=126 +VAR_STAT_NB_ELITE_FOUR=174 +VAR_STAT_NB_WONDERTRADES=164 +VAR_STAT_CLOWN_TIP_TOTAL=100 +VAR_STAT_NB_SANDCASTLES=163 +VAR_STAT_GAMBLER_WINS=43 +VAR_STAT_GAMBLER_LOSSES=44 +VAR_STAT_HOTELS_SPENT=225 +VAR_NB_EGGS_HATCHED=298 + + +VAR_STAT_QUESTS_ACCEPTED=96 +VAR_STAT_QUESTS_COMPLETED=98 +VAR_NB_ROCKET_MISSIONS = 286 + +VAR_BOUTIQUE_OUTFIT=290 +VAR_FISHING_CONTEST_RECORD=294 +VAR_FISHING_CONTEST_NERF=333 + + + +VAR_STAT_NB_SECRETS=193 +VAR_STAT_FUSION_QUIZ_HIGHEST_SCORE=267 +VAR_STAT_FUSION_QUIZ_NB_TIMES=268 +VAR_STAT_FUSION_QUIZ_TOTAL_PTS=269 +VAR_KARMA=222 +VAR_NB_QUEST_ACTIVE=97 +VAR_NB_QUEST_COMPLETED=98 + + +VAR_LUNAR_FEATHERS=282 + +VAR_FOSSIL=271 + +VAR_SSANNE_MENU=313 +VAR_TEMP_SSANNE_ORDER=314 +VAR_TEMP_SSANNE_PLATE=325 +VAR_SSANNE_DISHES_HELD_ARRAY=316 + +VAR_BATTLE_TOWER_MIN_BST = 257 +VAR_BATTLE_TOWER_MAX_BST = 258 + +VAR_GALLERY_FEATURED_ARTIST = 259 +VAR_GALLERY_FEATURED_SPRITES = 260 +VAR_GALLERY_ALL_ARTIST_SPRITES = 261 +VAR_GALLERY_SELECTED_ARTIST = 263 +VAR_NEXT_ARTIST_FORMATTED = 264 + +VAR_RADIO_POINTS=266 +VAR_TRAINER_GENDER=52 +VAR_TRAINER_AGE=99 +VAR_ROCKET_NAME=25 + +VAR_NB_CRIMES_REPORTED=300 +VAR_EXOTIC_POKEMON_ID=327 +VAR_TYPE_EXPERTS_BEATEN=332 +TOTAL_NB_TYPE_EXPERTS=331 + +#Randomizer +VAR_RANDOMIZER_WILD_POKE_BST=197 +VAR_RANDOMIZER_TRAINER_BST=195 +VAR_GYM_TYPES_ARRAY=151 +VAR_CURRENT_GYM_TYPE=152 + +#constellations +VAR_CONSTELLATION_IVYSAUR=301 +VAR_CONSTELLATION_WARTORTLE=302 +VAR_CONSTELLATION_ARCANINE=303 +VAR_CONSTELLATION_MACHOKE=304 +VAR_CONSTELLATION_RAPIDASH=305 +VAR_CONSTELLATION_GYARADOS=306 +VAR_CONSTELLATION_ARTICUNO=307 +VAR_CONSTELLATION_MEW=308 +VAR_CONSTELLATION_POLITOED=309 +VAR_CONSTELLATION_URSARING=310 +VAR_CONSTELLATION_LUGIA=311 +VAR_CONSTELLATION_HOOH=312 +VAR_CONSTELLATION_CELEBI=313 +VAR_CONSTELLATION_SLAKING=314 +VAR_CONSTELLATION_JIRACHI=315 +VAR_CONSTELLATION_TYRANTRUM=316 +VAR_CONSTELLATION_SHARPEDO=317 +VAR_CONSTELLATION_ARCEUS=318 + +VAR_LATEST_CONSTELLATION=319 +VAR_TRAINER_CARD_BACKGROUND_PRICE=329 +VAR_GALLERY_TEAM_FLAGS=330 + +VAR_REGI_PUZZLE_SWITCH_PRESSED = 1122 +############## +# COMMON EVENTS +################ +COMMON_EVENT_REGI_TABLET = 84 +COMMON_EVENT_SILHOUETTE = 87 +COMMON_EVENT_HOTEL = 12 +COMMON_EVENT_SINGLESPECIES_MODE = 73 +COMMON_EVENT_OUTFIT = 80 +COMMON_EVENT_FIX_GAME = 16 +COMMON_EVENT_IDLE_HAT = 100 +COMMON_EVENT_PINKAN_WHISTLE = 106 +COMMON_EVENT_PINKAN_BACK_TO_BEGIN = 103 \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Fusion/Fusing.rb b/Data/Scripts/998_InfiniteFusion/Fusion/Fusing.rb new file mode 100644 index 000000000..67dabe82b --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Fusion/Fusing.rb @@ -0,0 +1,323 @@ +def getPokemonPositionInParty(pokemon) + for i in 0..$Trainer.party.length + if $Trainer.party[i] == pokemon + return i + end + end + return -1 +end + +# don't remember why there's two Supersplicers arguments.... probably a mistake +def pbDNASplicing(pokemon, scene, item = :DNASPLICERS) + is_supersplicer = isSuperSplicersMechanics(item) + + playingBGM = $game_system.getPlayingBGM + dexNumber = pokemon.species_data.id_number + if (pokemon.species_data.id_number <= NB_POKEMON) + if pokemon.fused != nil + if $Trainer.party.length >= 6 + scene.pbDisplay(_INTL("Your party is full! You can't unfuse {1}.", pokemon.name)) + return false + else + $Trainer.party[$Trainer.party.length] = pokemon.fused + pokemon.fused = nil + pokemon.form = 0 + scene.pbHardRefresh + scene.pbDisplay(_INTL("{1} changed Forme!", pokemon.name)) + return true + end + else + chosen = scene.pbChoosePokemon(_INTL("Fuse with which Pokémon?")) + if chosen >= 0 + poke2 = $Trainer.party[chosen] + if (poke2.species_data.id_number <= NB_POKEMON) && poke2 != pokemon + # check if fainted + + if pokemon.egg? || poke2.egg? + scene.pbDisplay(_INTL("It's impossible to fuse an egg!")) + return false + end + if pokemon.hp == 0 || poke2.hp == 0 + scene.pbDisplay(_INTL("A fainted Pokémon cannot be fused!")) + return false + end + + selectedHead = selectFusion(pokemon, poke2, is_supersplicer) + if selectedHead == -1 # cancelled + return false + end + if selectedHead == nil # can't fuse (egg, etc.) + scene.pbDisplay(_INTL("It won't have any effect.")) + return false + end + selectedBase = selectedHead == pokemon ? poke2 : pokemon + + firstOptionSelected = selectedHead == pokemon + if !firstOptionSelected + chosen = getPokemonPositionInParty(pokemon) + if chosen == -1 + scene.pbDisplay(_INTL("There was an error...")) + return false + end + end + + if (Kernel.pbConfirmMessage(_INTL("Fuse {1} and {2}?", selectedHead.name, selectedBase.name))) + pbFuse(selectedHead, selectedBase, item) + pbRemovePokemonAt(chosen) + scene.pbHardRefresh + pbBGMPlay(playingBGM) + return true + end + + elsif pokemon == poke2 + scene.pbDisplay(_INTL("{1} can't be fused with itself!", pokemon.name)) + return false + else + scene.pbDisplay(_INTL("{1} can't be fused with {2}.", poke2.name, pokemon.name)) + return false + end + else + return false + end + end + else + # UNFUSE + return true if pbUnfuse(pokemon, scene, is_supersplicer) + end +end + +def selectFusion(pokemon, poke2, supersplicers = false) + return nil if !pokemon.is_a?(Pokemon) || !poke2.is_a?(Pokemon) + return nil if pokemon.egg? || poke2.egg? + + selectorWindow = FusionPreviewScreen.new(poke2, pokemon, supersplicers) # PictureWindow.new(picturePath) + selectedHead = selectorWindow.getSelection + selectorWindow.dispose + return selectedHead +end + +# firstOptionSelected= selectedHead == pokemon +# selectedBody = selectedHead == pokemon ? poke2 : pokemon +# newid = (selectedBody.species_data.id_number) * NB_POKEMON + selectedHead.species_data.id_number + +# def pbFuse(pokemon, poke2, supersplicers = false) +# newid = (pokemon.species_data.id_number) * NB_POKEMON + poke2.species_data.id_number +# previewwindow = FusionPreviewScreen.new(pokemon, poke2)#PictureWindow.new(picturePath) +# +# if (Kernel.pbConfirmMessage(_INTL("Fuse the two Pokémon?", newid))) +# previewwindow.dispose +# fus = PokemonFusionScene.new +# if (fus.pbStartScreen(pokemon, poke2, newid)) +# returnItemsToBag(pokemon, poke2) +# fus.pbFusionScreen(false, supersplicers) +# $game_variables[126] += 1 #fuse counter +# fus.pbEndScreen +# return true +# end +# else +# previewwindow.dispose +# return false +# end +# end + +def pbFuse(pokemon_body, pokemon_head, splicer_item) + use_supersplicers_mechanics = isSuperSplicersMechanics(splicer_item) + + newid = (pokemon_body.species_data.id_number) * NB_POKEMON + pokemon_head.species_data.id_number + fus = PokemonFusionScene.new + + if (fus.pbStartScreen(pokemon_body, pokemon_head, newid, splicer_item)) + returnItemsToBag(pokemon_body, pokemon_head) + fus.pbFusionScreen(false, use_supersplicers_mechanics) + $game_variables[VAR_FUSE_COUNTER] += 1 # fuse counter + fus.pbEndScreen + return true + end +end + +# Todo: refactor this, holy shit this is a mess +def pbUnfuse(pokemon, scene, supersplicers, pcPosition = nil) + if pokemon.species_data.id_number > (NB_POKEMON * NB_POKEMON) + NB_POKEMON # triple fusion + scene.pbDisplay(_INTL("{1} cannot be unfused.", pokemon.name)) + return false + end + if pokemon.owner.name == "RENTAL" + scene.pbDisplay(_INTL("You cannot unfuse a rental pokémon!")) + return + end + + pokemon.spriteform_body = nil + pokemon.spriteform_head = nil + + bodyPoke = getBasePokemonID(pokemon.species_data.id_number, true) + headPoke = getBasePokemonID(pokemon.species_data.id_number, false) + + if (pokemon.foreign?($Trainer)) # && !canunfuse + scene.pbDisplay(_INTL("You can't unfuse a Pokémon obtained in a trade!")) + return false + else + if Kernel.pbConfirmMessageSerious(_INTL("Should {1} be unfused?", pokemon.name)) + keepInParty = 0 + if $Trainer.party.length >= 6 && !pcPosition + + message = "Your party is full! Keep which Pokémon in party?" + message = "Your party is full! Keep which Pokémon in party? The other will be released." if isOnPinkanIsland() + scene.pbDisplay(_INTL(message)) + selectPokemonMessage = "Select a Pokémon to keep in your party." + selectPokemonMessage = "Select a Pokémon to keep in your party. The other will be released" if isOnPinkanIsland() + choice = Kernel.pbMessage(selectPokemonMessage, [_INTL("{1}", PBSpecies.getName(bodyPoke)), _INTL("{1}", PBSpecies.getName(headPoke)), "Cancel"], 2) + if choice == 2 + return false + else + keepInParty = choice + end + end + + scene.pbDisplay(_INTL("Unfusing ... ")) + scene.pbDisplay(_INTL(" ... ")) + scene.pbDisplay(_INTL(" ... ")) + + if pokemon.exp_when_fused_head == nil || pokemon.exp_when_fused_body == nil + new_level = calculateUnfuseLevelOldMethod(pokemon, supersplicers) + body_level = new_level + head_level = new_level + poke1 = Pokemon.new(bodyPoke, body_level) + poke2 = Pokemon.new(headPoke, head_level) + else + exp_body = pokemon.exp_when_fused_body + pokemon.exp_gained_since_fused + exp_head = pokemon.exp_when_fused_head + pokemon.exp_gained_since_fused + + poke1 = Pokemon.new(bodyPoke, pokemon.level) + poke2 = Pokemon.new(headPoke, pokemon.level) + poke1.exp = exp_body + poke2.exp = exp_head + end + body_level = poke1.level + head_level = poke2.level + + pokemon.exp_gained_since_fused = 0 + pokemon.exp_when_fused_head = nil + pokemon.exp_when_fused_body = nil + + if pokemon.shiny? + pokemon.shiny = false + if pokemon.bodyShiny? && pokemon.headShiny? + pokemon.shiny = true + poke2.shiny = true + pokemon.natural_shiny = true if pokemon.natural_shiny && !pokemon.debug_shiny + poke2.natural_shiny = true if pokemon.natural_shiny && !pokemon.debug_shiny + elsif pokemon.bodyShiny? + pokemon.shiny = true + poke2.shiny = false + pokemon.natural_shiny = true if pokemon.natural_shiny && !pokemon.debug_shiny + elsif pokemon.headShiny? + poke2.shiny = true + pokemon.shiny = false + poke2.natural_shiny = true if pokemon.natural_shiny && !pokemon.debug_shiny + else + # shiny was obtained already fused + if rand(2) == 0 + pokemon.shiny = true + else + poke2.shiny = true + end + end + end + + fused_pokemon_learned_moved = pokemon.learned_moves + pokemon.learned_moves = fused_pokemon_learned_moved + poke2.learned_moves = fused_pokemon_learned_moved + + pokemon.ability_index = pokemon.body_original_ability_index if pokemon.body_original_ability_index + poke2.ability_index = pokemon.head_original_ability_index if pokemon.head_original_ability_index + + pokemon.ability2_index = nil + pokemon.ability2 = nil + poke2.ability2_index = nil + poke2.ability2 = nil + + pokemon.debug_shiny = true if pokemon.debug_shiny && pokemon.body_shiny + poke2.debug_shiny = true if pokemon.debug_shiny && poke2.head_shiny + + pokemon.body_shiny = false + pokemon.head_shiny = false + + if !pokemon.shiny? + pokemon.debug_shiny = false + end + if !poke2.shiny? + poke2.debug_shiny = false + end + + if $Trainer.party.length >= 6 + if (keepInParty == 0) + if isOnPinkanIsland() + scene.pbDisplay(_INTL("{1} was released.", poke2.name)) + else + $PokemonStorage.pbStoreCaught(poke2) + scene.pbDisplay(_INTL("{1} was sent to the PC.", poke2.name)) + end + else + poke2 = Pokemon.new(bodyPoke, body_level) + poke1 = Pokemon.new(headPoke, head_level) + + # Fusing from PC + if pcPosition != nil + box = pcPosition[0] + index = pcPosition[1] + # todo: store at next available position from current position + $PokemonStorage.pbStoreCaught(poke2) + else + # Fusing from party + if isOnPinkanIsland() + scene.pbDisplay(_INTL("{1} was released.", poke2.name)) + else + $PokemonStorage.pbStoreCaught(poke2) + scene.pbDisplay(_INTL("{1} was sent to the PC.", poke2.name)) + end + end + end + else + if pcPosition != nil + box = pcPosition[0] + index = pcPosition[1] + # todo: store at next available position from current position + $PokemonStorage.pbStoreCaught(poke2) + else + Kernel.pbAddPokemonSilent(poke2, poke2.level) + end + end + + # On ajoute les poke au pokedex + $Trainer.pokedex.set_seen(poke1.species) + $Trainer.pokedex.set_owned(poke1.species) + $Trainer.pokedex.set_seen(poke2.species) + $Trainer.pokedex.set_owned(poke2.species) + + pokemon.species = poke1.species + pokemon.level = poke1.level + pokemon.name = poke1.name + pokemon.moves = poke1.moves + pokemon.obtain_method = 0 + poke1.obtain_method = 0 + + # scene.pbDisplay(_INTL(p1.to_s + " " + p2.to_s)) + scene.pbHardRefresh + scene.pbDisplay(_INTL("Your Pokémon were successfully unfused! ")) + return true + end + end +end# frozen_string_literal: true + + +def returnItemsToBag(pokemon, poke2) + + it1 = pokemon.item + it2 = poke2.item + + $PokemonBag.pbStoreItem(it1, 1) if it1 != nil + $PokemonBag.pbStoreItem(it2, 1) if it2 != nil + + pokemon.item = nil + poke2.item = nil +end diff --git a/Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/FusedSpecies.rb b/Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/FusedSpecies.rb new file mode 100644 index 000000000..82a96f6ad --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/FusedSpecies.rb @@ -0,0 +1,403 @@ +# module GameData +# class FusedSpecies < GameData::Species +# attr_reader :growth_rate +# attr_reader :body_pokemon +# attr_reader :head_pokemon +# +# def initialize(id) +# if id.is_a?(Integer) +# body_id = getBodyID(id) +# head_id = getHeadID(id, body_id) +# pokemon_id = getFusedPokemonIdFromDexNum(body_id, head_id) +# return GameData::FusedSpecies.new(pokemon_id) +# end +# head_id = get_head_number_from_symbol(id) +# body_id = get_body_number_from_symbol(id) +# +# @body_pokemon = GameData::Species.get(body_id) +# @head_pokemon = GameData::Species.get(head_id) +# +# @id = id +# @id_number = calculate_dex_number() +# @species = @id +# @form = 0 +# @real_name = calculate_name() +# @real_form_name = nil +# +# @type1 = calculate_type1() +# @type2 = calculate_type2() +# +# #Stats +# @base_stats = calculate_base_stats() +# @evs = calculate_evs() +# adjust_stats_with_evs() +# +# @base_exp = calculate_base_exp() +# @growth_rate = calculate_growth_rate() +# @gender_ratio = calculate_gender() #todo +# @catch_rate = calculate_catch_rate() +# @happiness = calculate_base_happiness() +# +# #Moves +# @moves = calculate_moveset() +# @tutor_moves = calculate_tutor_moves() # hash[:tutor_moves] || [] +# @egg_moves = calculate_egg_moves() # hash[:egg_moves] || [] +# +# #Abilities +# @abilities = calculate_abilities() # hash[:abilities] || [] +# @hidden_abilities = calculate_hidden_abilities() # hash[:hidden_abilities] || [] +# +# #wild held items +# @wild_item_common = get_wild_item(@head_pokemon.wild_item_common, @body_pokemon.wild_item_common) # hash[:wild_item_common] +# @wild_item_uncommon = get_wild_item(@head_pokemon.wild_item_uncommon, @body_pokemon.wild_item_uncommon) # hash[:wild_item_uncommon] +# @wild_item_rare = get_wild_item(@head_pokemon.wild_item_rare, @body_pokemon.wild_item_rare) # hash[:wild_item_rare] +# +# @evolutions = calculate_evolutions() # hash[:evolutions] || [] +# +# #breeding +# @egg_groups = [:Undiscovered] #calculate_egg_groups() # hash[:egg_groups] || [:Undiscovered] +# @hatch_steps = calculate_hatch_steps() # hash[:hatch_steps] || 1 +# @incense = nil #hash[:incense] +# +# #pokedex +# @pokedex_form = @form #ignored +# @real_category = calculate_category() +# @real_pokedex_entry = calculate_dex_entry() +# @height = average_values(@head_pokemon.height, @body_pokemon.height) +# @weight = average_values(@head_pokemon.weight, @body_pokemon.weight) +# @color = @head_pokemon.color +# @shape = @body_pokemon.shape +# +# #sprite positioning +# @back_sprite_x = @body_pokemon.back_sprite_x +# @back_sprite_y = @body_pokemon.back_sprite_y +# @front_sprite_x = @body_pokemon.front_sprite_x +# @front_sprite_y = @body_pokemon.front_sprite_y +# @front_sprite_altitude = @body_pokemon.front_sprite_altitude +# @shadow_x = @body_pokemon.shadow_x +# @shadow_size = @body_pokemon.shadow_size +# +# # #unused attributes from Species class +# # +# # @shape = :Head +# # @habitat = :None +# # @generation = 0 +# # @mega_stone = nil +# # @mega_move = nil +# # @unmega_form = 0 +# # @mega_message = 0 +# end +# +# def get_body_number_from_symbol(id) +# return id.to_s.match(/\d+/)[0].to_i +# end +# +# def get_head_number_from_symbol(id) +# return id.to_s.match(/(?<=H)\d+/)[0].to_i +# end +# +# def get_body_species +# return @body_pokemon.id_number +# end +# +# def get_head_species +# return @head_pokemon.id_number +# end +# +# def get_body_species_symbol +# return @body_pokemon.id +# end +# +# def get_head_species_symbol +# return @head_pokemon.id +# end +# +# def adjust_stats_with_evs +# GameData::Stat.each_main do |s| +# @base_stats[s.id] = 1 if !@base_stats[s.id] || @base_stats[s.id] <= 0 +# @evs[s.id] = 0 if !@evs[s.id] || @evs[s.id] < 0 +# end +# end +# +# #FUSION CALCULATIONS +# def calculate_dex_number() +# return (@body_pokemon.id_number * NB_POKEMON) + @head_pokemon.id_number +# end +# +# def calculate_type1() +# return @head_pokemon.type2 if @head_pokemon.type1 == :NORMAL && @head_pokemon.type2 == :FLYING +# return @head_pokemon.type1 +# end +# +# def calculate_type2() +# return @body_pokemon.type1 if @body_pokemon.type2 == @type1 +# return @body_pokemon.type2 +# end +# +# def calculate_base_stats() +# head_stats = @head_pokemon.base_stats +# body_stats = @body_pokemon.base_stats +# +# fused_stats = {} +# +# #Head dominant stats +# fused_stats[:HP] = calculate_fused_stats(head_stats[:HP], body_stats[:HP]) +# fused_stats[:SPECIAL_DEFENSE] = calculate_fused_stats(head_stats[:SPECIAL_DEFENSE], body_stats[:SPECIAL_DEFENSE]) +# fused_stats[:SPECIAL_ATTACK] = calculate_fused_stats(head_stats[:SPECIAL_ATTACK], body_stats[:SPECIAL_ATTACK]) +# +# #Body dominant stats +# fused_stats[:ATTACK] = calculate_fused_stats(body_stats[:ATTACK], head_stats[:ATTACK]) +# fused_stats[:DEFENSE] = calculate_fused_stats(body_stats[:DEFENSE], head_stats[:DEFENSE]) +# fused_stats[:SPEED] = calculate_fused_stats(body_stats[:SPEED], head_stats[:SPEED]) +# +# return fused_stats +# end +# +# def calculate_base_exp() +# head_exp = @head_pokemon.base_exp +# body_exp = @body_pokemon.base_exp +# return average_values(head_exp, body_exp) +# end +# +# def calculate_catch_rate +# return get_lowest_value(@body_pokemon.catch_rate, @head_pokemon.catch_rate) +# end +# +# def calculate_base_happiness +# return @head_pokemon.happiness +# end +# +# def calculate_moveset +# return combine_arrays(@body_pokemon.moves, @head_pokemon.moves) +# end +# +# def calculate_egg_moves +# return combine_arrays(@body_pokemon.egg_moves, @head_pokemon.egg_moves) +# end +# +# def calculate_tutor_moves +# return combine_arrays(@body_pokemon.tutor_moves, @head_pokemon.tutor_moves) +# end +# +# def get_wild_item(body_item, head_item) +# rand_num = rand(2) +# if rand_num == 0 +# return body_item +# else +# return head_item +# end +# end +# +# def calculate_abilities() +# abilities_hash = [] +# +# ability1 = @body_pokemon.abilities[0] +# ability2 = @head_pokemon.abilities[0] +# abilities_hash << ability1 +# abilities_hash << ability2 +# return abilities_hash +# end +# +# # def calculate_abilities(pokemon1, pokemon2) +# # abilities_hash = [] +# # +# # ability1 = pokemon1.abilities[0] +# # ability2 = pokemon2.abilities[1] +# # if !ability2 +# # ability2 = pokemon2.abilities[0] +# # end +# # abilities_hash << ability1 +# # abilities_hash << ability2 +# # return abilities_hash +# # end +# +# def calculate_hidden_abilities() +# abilities_hash = [] +# +# #First two spots are the other abilities of the two pokemon +# ability1 = @body_pokemon.abilities[1] +# ability2 = @head_pokemon.abilities[1] +# ability1 = @body_pokemon.abilities[0] if !ability1 +# ability2 = @head_pokemon.abilities[0] if !ability2 +# +# abilities_hash << ability1 +# abilities_hash << ability2 +# +# #add the hidden ability for the two base pokemon +# hiddenAbility1 = @body_pokemon.hidden_abilities[0] +# hiddenAbility1 = ability1 if !hiddenAbility1 +# +# hiddenAbility2 = @head_pokemon.hidden_abilities[0] +# hiddenAbility2 = ability2 if !hiddenAbility2 +# +# abilities_hash << hiddenAbility1 +# abilities_hash << hiddenAbility2 +# return abilities_hash +# end +# +# def calculate_name() +# body_nat_dex = GameData::NAT_DEX_MAPPING[@body_pokemon.id_number] ? GameData::NAT_DEX_MAPPING[@body_pokemon.id_number] : @body_pokemon.id_number +# head_nat_dex = GameData::NAT_DEX_MAPPING[@head_pokemon.id_number] ? GameData::NAT_DEX_MAPPING[@head_pokemon.id_number] : @head_pokemon.id_number +# begin +# prefix = GameData::SPLIT_NAMES[head_nat_dex][0] +# suffix = GameData::SPLIT_NAMES[body_nat_dex][1] +# if prefix[-1] == suffix[0] +# prefix = prefix[0..-2] +# end +# suffix = suffix.capitalize if prefix.end_with?(" ") +# return prefix + suffix +# +# rescue +# print("species with error: " + @species.to_s) +# end +# +# end +# +# def calculate_evolutions() +# body_evolutions = @body_pokemon.evolutions +# head_evolutions = @head_pokemon.evolutions +# +# fused_evolutions = [] +# +# #body +# for evolution in body_evolutions +# evolutionSpecies = evolution[0] +# evolutionSpecies_dex = GameData::Species.get(evolutionSpecies).id_number +# fused_species = _INTL("B{1}H{2}", evolutionSpecies_dex, @head_pokemon.id_number) +# fused_evolutions << build_evolution_array(evolution, fused_species) +# end +# +# #head +# for evolution in head_evolutions +# evolutionSpecies = evolution[0] +# evolutionSpecies_dex = GameData::Species.get(evolutionSpecies).id_number +# fused_species = _INTL("B{1}H{2}", @body_pokemon.id_number, evolutionSpecies_dex) +# fused_evolutions << build_evolution_array(evolution, fused_species) +# end +# +# return fused_evolutions +# end +# +# #Change the evolution species depending if head & body and keep the rest of the data the same +# def build_evolution_array(evolution_data, new_species) +# fused_evolution_array = [] +# fused_evolution_array << new_species.to_sym +# +# #add the rest +# for data in evolution_data +# next if evolution_data.index(data) == 0 +# fused_evolution_array << data +# end +# return fused_evolution_array +# end +# +# def calculate_dex_entry +# body_entry = @body_pokemon.real_pokedex_entry.gsub(@body_pokemon.real_name, @real_name) +# head_entry = @head_pokemon.real_pokedex_entry.gsub(@head_pokemon.real_name, @real_name) +# +# return split_and_combine_text(body_entry, head_entry, ".") +# end +# +# def get_random_dex_entry() +# begin +# file_path = Settings::POKEDEX_ENTRIES_PATH +# json_data = File.read(file_path) +# all_body_entries = HTTPLite::JSON.parse(json_data) +# +# +# body_entry = all_body_entries[@body_pokemon.id_number.to_s].sample +# body_entry = body_entry.gsub(/#{@body_pokemon.real_name}/i, @real_name) +# body_entry = clean_json_string(body_entry).gsub(@body_pokemon.real_name, @real_name) +# +# head_entry = all_body_entries[@head_pokemon.id_number.to_s].sample +# head_entry = head_entry.gsub(/#{@head_pokemon.real_name}/i, @real_name) +# head_entry = clean_json_string(head_entry).gsub(@head_pokemon.real_name, @real_name) +# rescue +# body_entry = @body_pokemon.real_pokedex_entry.gsub(@body_pokemon.real_name, @real_name) +# head_entry = @head_pokemon.real_pokedex_entry.gsub(@head_pokemon.real_name, @real_name) +# end +# echoln body_entry +# echoln head_entry +# combined_entry = split_and_combine_text(body_entry, head_entry, ".") +# combined_entry += "." unless combined_entry.end_with?(".") +# return combined_entry +# end +# +# def calculate_egg_groups +# body_egg_groups = @body_pokemon.egg_groups +# head_egg_groups = @head_pokemon.egg_groups +# return :Undiscovered if body_egg_groups.include?(:Undiscovered) || head_egg_groups.include?(:Undiscovered) +# return combine_arrays(body_egg_groups, head_egg_groups) +# end +# +# def calculate_hatch_steps +# return average_values(@head_pokemon.hatch_steps, @body_pokemon.hatch_steps) +# end +# +# def calculate_evs() +# return average_map_values(@body_pokemon.evs, @head_pokemon.evs) +# end +# +# def calculate_category +# return split_and_combine_text(@body_pokemon.category, @head_pokemon.category, " ") +# end +# +# def calculate_growth_rate +# growth_rate_priority = [:Fast, :Medium, :Parabolic, :Fluctuating, :Erratic, :Slow] #todo rearrange order for balance? +# body_growth_rate = @body_pokemon.growth_rate +# head_growth_rate = @head_pokemon.growth_rate +# base_growth_rates = [body_growth_rate, head_growth_rate] +# for rate in growth_rate_priority +# return rate if base_growth_rates.include?(rate) +# end +# return :Medium +# end +# +# #TODO +# # ################## UNFINISHED #################### +# def calculate_gender +# return :Genderless +# end +# +# ############################# UTIL METHODS ############################### +# +# #Takes 2 strings, splits and combines them using the beginning of the first one and the end of the second one +# # (for example for pokedex entries) +# def split_and_combine_text(beginingText_full, endText_full, separator) +# beginingText_split = beginingText_full.split(separator, 2) +# endText_split = endText_full.split(separator, 2) +# +# beginningText = beginingText_split[0] +# endText = endText_split[1] && endText_split[1] != "" ? endText_split[1] : endText_split[0] +# return beginningText + separator + " " + endText +# end +# +# def calculate_fused_stats(dominantStat, otherStat) +# return ((2 * dominantStat) / 3) + (otherStat / 3).floor +# end +# +# def average_values(value1, value2) +# return ((value1 + value2) / 2).floor +# end +# +# def average_map_values(map1, map2) +# averaged_map = map1.merge(map2) do |key, value1, value2| +# ((value1 + value2) / 2.0).floor +# end +# return averaged_map +# end +# +# def get_highest_value(value1, value2) +# return value1 > value2 ? value1 : value2 +# end +# +# def get_lowest_value(value1, value2) +# return value1 < value2 ? value1 : value2 +# end +# +# def combine_arrays(array1, array2) +# return array1 + array2 +# end +# +# end +# end diff --git a/Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/fused_species_integration.rb b/Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/fused_species_integration.rb new file mode 100644 index 000000000..e2c87216d --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Fusion/Fusion data/fused_species_integration.rb @@ -0,0 +1,31 @@ +# module GameData +# module ClassMethods +# def get(other) +# validate other => [Symbol, self, String, Integer] +# return other if other.is_a?(self) +# other = other.to_sym if other.is_a?(String) +# +# if other.to_s.match?(/\AB\d+H\d+\z/) +# species = GameData::FusedSpecies.new(other) +# return species +# end +# +# if other.is_a?(Integer) && self == GameData::Species +# if other > NB_POKEMON +# body_id = getBodyID(other) +# head_id = getHeadID(other, body_id) +# pokemon_id = getFusedPokemonIdFromDexNum(body_id, head_id) +# return GameData::FusedSpecies.new(pokemon_id) +# end +# end +# +# if !self::DATA.has_key?(other) +# # echoln _INTL("Unknown ID {1}.", other) +# return self::get(:PIKACHU) +# end +# +# raise "Unknown ID #{other}." unless self::DATA.has_key?(other) +# return self::DATA[other] +# end +# end +# end diff --git a/Data/Scripts/998_InfiniteFusion/Fusion/fusion_utils.rb b/Data/Scripts/998_InfiniteFusion/Fusion/fusion_utils.rb new file mode 100644 index 000000000..b3a24995a --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Fusion/fusion_utils.rb @@ -0,0 +1,410 @@ +def is_fusion_of_any(species_id, pokemonList) + is_species = false + for fusionPokemon in pokemonList + if is_fusion_of(species_id, fusionPokemon) + is_species = true + end + end + return is_species +end + +def is_fusion_of(checked_species, checked_against) + return species_has_body_of(checked_species, checked_against) || species_has_head_of(checked_species, checked_against) +end + +def is_species(checked_species, checked_against) + return checked_species == checked_against +end + +def species_has_body_of(checked_species, checked_against) + if !species_is_fusion(checked_species) + return is_species(checked_species, checked_against) + end + bodySpecies = get_body_species_from_symbol(checked_species) + ret = bodySpecies == checked_against + #echoln _INTL("{1} HAS BODY OF {2} : {3} (body is {4})",checked_species,checked_against,ret,bodySpecies) + return ret +end + +def species_has_head_of(checked_species, checked_against) + if !species_is_fusion(checked_species) + return is_species(checked_species, checked_against) + end + headSpecies = get_head_species_from_symbol(checked_species) + ret = headSpecies == checked_against + #echoln _INTL("{1} HAS HEAD OF {2} : {3}",checked_species,checked_against,ret) + return ret +end + +def species_is_fusion(species_id) + dex_number = get_dex_number(species_id) + return dex_number > NB_POKEMON && dex_number < Settings::ZAPMOLCUNO_NB +end + +def get_dex_number(species_id) + return GameData::Species.get(species_id).id_number +end + +def getBodyID(species, nb_pokemon = NB_POKEMON) + if species.is_a?(Integer) + dexNum = species + else + dexNum = getDexNumberForSpecies(species) + end + if dexNum % nb_pokemon == 0 + return (dexNum / nb_pokemon) - 1 + end + return (dexNum / nb_pokemon).round +end + +def getHeadID(species, bodyId = nil, nb_pokemon = NB_POKEMON) + if species.is_a?(Integer) + fused_dexNum = species + else + fused_dexNum = getDexNumberForSpecies(species) + end + + if bodyId == nil + bodyId = getBodyID(species) + end + body_dexNum = getDexNumberForSpecies(bodyId) + + calculated_number = (fused_dexNum - (body_dexNum * nb_pokemon)).round + return calculated_number == 0 ? nb_pokemon : calculated_number +end + +def get_fusion_id(head_number, body_number) + return "B#{body_number}H#{head_number}".to_sym +end + +def get_body_id_from_symbol(id) + split_id = id.to_s.match(/\d+/) + if !split_id #non-fusion + return GameData::Species.get(id).id_number + end + return split_id[0].to_i +end + +def get_head_id_from_symbol(id) + split_id = id.to_s.match(/(?<=H)\d+/) + if !split_id #non-fusion + return GameData::Species.get(id).id_number + end + + return split_id[0].to_i +end + +def obtainPokemonSpritePath(id, includeCustoms = true) + head = getBasePokemonID(param.to_i, false) + body = getBasePokemonID(param.to_i, true) + + return obtainPokemonSpritePath(body, head, includeCustoms) +end + +def obtainPokemonSpritePath(bodyId, headId, include_customs = true) + #download_pokemon_sprite_if_missing(bodyId, headId) + picturePath = _INTL("Graphics/Battlers/{1}/{1}.{2}.png", headId, bodyId) + + if include_customs && customSpriteExistsBodyHead(bodyId, headId) + pathCustom = getCustomSpritePath(bodyId, headId) + if (pbResolveBitmap(pathCustom)) + picturePath = pathCustom + end + end + return picturePath +end + +def getCustomSpritePath(body, head) + return _INTL("#{Settings::CUSTOM_BATTLERS_FOLDER_INDEXED}{1}/{1}.{2}.png", head, body) +end + +def customSpriteExistsForm(species, form_id_head = nil, form_id_body = nil) + head = getBasePokemonID(species, false) + body = getBasePokemonID(species, true) + + folder = head.to_s + + folder += "_" + form_id_head.to_s if form_id_head + + spritename = head.to_s + spritename += "_" + form_id_head.to_s if form_id_head + spritename += "." + body.to_s + spritename += "_" + form_id_body.to_s if form_id_body + + pathCustom = _INTL("Graphics/.CustomBattlers/indexed/{1}/{2}.png", folder, spritename) + return true if pbResolveBitmap(pathCustom) != nil + return download_custom_sprite(head, body) != nil +end + +def get_fusion_spritename(head_id, body_id, alt_letter = "") + return "#{head_id}.#{body_id}#{alt_letter}" +end + +def customSpriteExistsSpecies(species) + head = getBasePokemonID(species, false) + body = getBasePokemonID(species, true) + return customSpriteExists(body, head) + # pathCustom = getCustomSpritePath(body, head) + # + # return true if pbResolveBitmap(pathCustom) != nil + # return download_custom_sprite(head, body) != nil +end + +def getRandomCustomFusion(returnRandomPokemonIfNoneFound = true, customPokeList = [], maxPoke = -1, recursionLimit = 3) + if customPokeList.length == 0 + customPokeList = getCustomSpeciesList(false) + end + randPoke = [] + if customPokeList.length >= 5000 + chosen = false + i = 0 #loop pas plus que 3 fois pour pas lag + while chosen == false + fusedPoke = customPokeList[rand(customPokeList.length)] + poke1 = getBasePokemonID(fusedPoke, false) + poke2 = getBasePokemonID(fusedPoke, true) + + if ((poke1 <= maxPoke && poke2 <= maxPoke) || i >= recursionLimit) || maxPoke == -1 + randPoke << getBasePokemonID(fusedPoke, false) + randPoke << getBasePokemonID(fusedPoke, true) + chosen = true + end + end + else + if returnRandomPokemonIfNoneFound + randPoke << rand(maxPoke) + 1 + randPoke << rand(maxPoke) + 1 + end + end + return randPoke +end + +def checkIfCustomSpriteExistsByPath(path) + return true if pbResolveBitmap(path) != nil +end + +def customSpriteExistsBodyHead(body, head) + pathCustom = getCustomSpritePath(body, head) + + return true if pbResolveBitmap(pathCustom) != nil + return download_custom_sprite(head, body) != nil +end + +def customSpriteExistsSpecies(species) + body_id = getBodyID(species) + head_id = getHeadID(species, body_id) + fusion_id = get_fusion_symbol(head_id, body_id) + return $game_temp.custom_sprites_list.include?(fusion_id) +end + +def customSpriteExists(body, head) + fusion_id = get_fusion_symbol(head, body) + return $game_temp.custom_sprites_list.include?(fusion_id) +end + +#shortcut for using in game events because of script characters limit +def dexNum(species) + return getDexNumberForSpecies(species) +end + +def isTripleFusion?(num) + return num >= Settings::ZAPMOLCUNO_NB +end + +def isFusion(num) + return num > Settings::NB_POKEMON && !isTripleFusion?(num) +end + +def isSpeciesFusion(species) + num = getDexNumberForSpecies(species) + return isFusion(num) +end + +def getRandomLocalFusion() + spritesList = [] + $PokemonGlobal.alt_sprite_substitutions.each_value do |value| + if value.is_a?(PIFSprite) + spritesList << value + end + end + return spritesList.sample +end + +def getRandomFusionForIntro() + random_pokemon = $game_temp.custom_sprites_list.keys.sample || :PIKACHU + alt_letter = $game_temp.custom_sprites_list[random_pokemon] + body_id = get_body_number_from_symbol(random_pokemon) + head_id = get_head_number_from_symbol(random_pokemon) + return PIFSprite.new(:CUSTOM, head_id, body_id, alt_letter) +end + +def getSpeciesIdForFusion(head_number, body_number) + return (body_number) * Settings::NB_POKEMON + head_number +end + +def get_body_species_from_symbol(fused_id) + body_num = get_body_number_from_symbol(fused_id) + return GameData::Species.get(body_num).species +end + +def get_head_species_from_symbol(fused_id) + head_num = get_head_number_from_symbol(fused_id) + return GameData::Species.get(head_num).species +end + +def get_body_number_from_symbol(id) + dexNum = getDexNumberForSpecies(id) + return dexNum if !isFusion(dexNum) + id.to_s.match(/\d+/)[0] + return id.to_s.match(/\d+/)[0].to_i +end + +def get_head_number_from_symbol(id) + dexNum = getDexNumberForSpecies(id) + return dexNum if !isFusion(dexNum) + return id.to_s.match(/(?<=H)\d+/)[0].to_i +end + +def get_fusion_symbol(head_id, body_id) + return "B#{body_id}H#{head_id}".to_sym +end + +def getFusionSpecies(body, head) + body_num = getDexNumberForSpecies(body) + head_num = getDexNumberForSpecies(head) + id = body_num * Settings::NB_POKEMON + head_num + return GameData::Species.get(id) +end + +def getDexNumberForSpecies(species) + return species if species.is_a?(Integer) + if species.is_a?(Symbol) + dexNum = GameData::Species.get(species).id_number + elsif species.is_a?(Pokemon) + dexNum = GameData::Species.get(species.species).id_number + elsif species.is_a?(GameData::Species) + return species.id_number + else + dexNum = species + end + return dexNum +end + +def getFusedPokemonIdFromDexNum(body_dex, head_dex) + return ("B" + body_dex.to_s + "H" + head_dex.to_s).to_sym +end + +def getFusedPokemonIdFromSymbols(body_dex, head_dex) + bodyDexNum = GameData::Species.get(body_dex).id_number + headDexNum = GameData::Species.get(head_dex).id_number + return getFusedPokemonIdFromDexNum(bodyDexNum, headDexNum) +end + +def generateFusionIcon(dexNum, path) + begin + IO.copy_stream(dexNum, path) + return true + rescue + return false + end +end + +def ensureFusionIconExists + directory_name = "Graphics/Pokemon/FusionIcons" + Dir.mkdir(directory_name) unless File.exists?(directory_name) +end + +def addNewTripleFusion(pokemon1, pokemon2, pokemon3, level = 1) + return if !pokemon1 + return if !pokemon2 + return if !pokemon3 + + if pbBoxesFull? + pbMessage(_INTL("There's no more room for Pokémon!\1")) + pbMessage(_INTL("The Pokémon Boxes are full and can't accept any more!")) + return false + end + + pokemon = TripleFusion.new(pokemon1, pokemon2, pokemon3, level) + pokemon.calc_stats + pbMessage(_INTL("{1} obtained {2}!\\me[Pkmn get]\\wtnp[80]\1", $Trainer.name, pokemon.name)) + pbNicknameAndStore(pokemon) + #$Trainer.pokedex.register(pokemon) + return true +end + +def get_triple_fusion_components(species_id) + dex_num = GameData::Species.get(species_id).id_number + case dex_num + when Settings::ZAPMOLCUNO_NB + return [144,145,146] + when Settings::ZAPMOLCUNO_NB + 1 + return [144,145,146] + when Settings::ZAPMOLCUNO_NB + 2 + return [243,244,245] + when Settings::ZAPMOLCUNO_NB + 3 + return [340,341,342] + when Settings::ZAPMOLCUNO_NB + 4 + return [343,344,345] + when Settings::ZAPMOLCUNO_NB + 5 + return [349,350,351] + when Settings::ZAPMOLCUNO_NB + 6 + return [151,251,381] + when Settings::ZAPMOLCUNO_NB + 11 + return [150,348,380] + #starters + when Settings::ZAPMOLCUNO_NB + 7 + return [3,6,9] + when Settings::ZAPMOLCUNO_NB + 8 + return [154,157,160] + when Settings::ZAPMOLCUNO_NB + 9 + return [278,281,284] + when Settings::ZAPMOLCUNO_NB + 10 + return [318,321,324] + #starters prevos + when Settings::ZAPMOLCUNO_NB + 12 + return [1,4,7] + when Settings::ZAPMOLCUNO_NB + 13 + return [2,5,8] + when Settings::ZAPMOLCUNO_NB + 14 + return [152,155,158] + when Settings::ZAPMOLCUNO_NB + 15 + return [153,156,159] + when Settings::ZAPMOLCUNO_NB + 16 + return [276,279,282] + when Settings::ZAPMOLCUNO_NB + 17 + return [277,280,283] + when Settings::ZAPMOLCUNO_NB + 18 + return [316,319,322] + when Settings::ZAPMOLCUNO_NB + 19 + return [317,320,323] + when Settings::ZAPMOLCUNO_NB + 20 #birdBoss Left + return [] + when Settings::ZAPMOLCUNO_NB + 21 #birdBoss middle + return [144,145,146] + when Settings::ZAPMOLCUNO_NB + 22 #birdBoss right + return [] + when Settings::ZAPMOLCUNO_NB + 23 #sinnohboss left + return [] + when Settings::ZAPMOLCUNO_NB + 24 #sinnohboss middle + return [343,344,345] + when Settings::ZAPMOLCUNO_NB + 25 #sinnohboss right + return [] + when Settings::ZAPMOLCUNO_NB + 25 #cardboard + return [] + when Settings::ZAPMOLCUNO_NB + 26 #cardboard + return [] + when Settings::ZAPMOLCUNO_NB + 27 #Triple regi + return [447,448,449] + #Triple Kalos 1 + when Settings::ZAPMOLCUNO_NB + 28 + return [479,482,485] + when Settings::ZAPMOLCUNO_NB + 29 + return [480,483,486] + when Settings::ZAPMOLCUNO_NB + 30 + return [481,484,487] + else + return [000] + end + +end + diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ClothesMart.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ClothesMart.rb new file mode 100644 index 000000000..49d78f0ca --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ClothesMart.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +def pokemart_clothes_shop(current_city = nil, include_defaults = true) + current_city = pbGet(VAR_CURRENT_MART) if !current_city + echoln current_city + current_city = :PEWTER if !current_city.is_a?(Symbol) + current_city_tag = current_city.to_s.downcase + selector = OutfitSelector.new + list = selector.generate_clothes_choice( + baseOptions = include_defaults, + additionalIds = [], + additionalTags = [current_city_tag], + filterOutTags = []) + clothesShop(list) +end + +def pokemart_hat_shop(include_defaults = true) + current_city = pbGet(VAR_CURRENT_MART) + current_city = :PEWTER if !current_city.is_a?(Symbol) + current_city_tag = current_city.to_s.downcase + selector = OutfitSelector.new + list = selector.generate_hats_choice( + baseOptions = include_defaults, + additionalIds = [], + additionalTags = [current_city_tag], + filterOutTags = []) + + hatShop(list) +end diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ExclusiveItems.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ExclusiveItems.rb new file mode 100644 index 000000000..cabf53ffb --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/ExclusiveItems.rb @@ -0,0 +1,53 @@ +def get_mart_exclusive_items(city) + items_list = [] + case city + when :PEWTER; + items_list = [:ROCKGEM, :NESTBALL] + when :VIRIDIAN; + items_list = [] + when :CERULEAN; + items_list = [:WATERGEM, :NETBALL, :PRETTYWING] + when :VERMILLION; + items_list = [:LOVEBALL, :ELECTRICGEM] + when :LAVENDER; + items_list = [:GHOSTGEM, :DARKGEM, :DUSKBALL] + when :CELADON; + items_list = [:GRASSGEM, :FLYINGGEM, :QUICKBALL, :TIMERBALL,] + when :FUCHSIA; + items_list = [:POISONGEM, :REPEATBALL] + when :SAFFRON; + items_list = [:PSYCHICGEM, :FIGHTINGGEM, :FRIENDBALL] + when :CINNABAR; + items_list = [:FIREGEM, :ICEGEM, :HEAVYBALL] + when :CRIMSON; + items_list = [:DRAGONGEM, :LEVELBALL] + when :GOLDENROD; + items_list = [:EVERSTONE, :MOONSTONE, :SUNSTONE, :DUSKSTONE, :DAWNSTONE, :SHINYSTONE] + when :AZALEA; + items_list = [:BUGGEM] + when :VIOLET; + items_list = [:FLYINGGEM, :STATUSBALL] + when :BLACKTHORN; + items_list = [:DRAGONGEM, :CANDYBALL] + when :CHERRYGROVE; + items_list = [:BUGGEM, :PUREBALL] + when :MAHOGANY; + items_list = [] + when :ECRUTEAK; + items_list = [:GHOSTGEM, :DARKGEM] + when :OLIVINE; + items_list = [] + when :CIANWOOD; + items_list = [] + when :KNOTISLAND; + items_list = [] + when :BOONISLAND; + items_list = [] + when :KINISLAND; + items_list = [] + when :CHRONOISLAND; + items_list = [] + end + return items_list +end# frozen_string_literal: true + diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/PokemartMapTransfers.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/PokemartMapTransfers.rb new file mode 100644 index 000000000..eb8556d58 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/PokeMart/PokemartMapTransfers.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +# Necessary dor setting the various events within the pokemart map, uses the numbers as wondertrade +def get_city_numerical_id(city_sym) + current_city_numerical = { + :PEWTER => 1, + :CERULEAN => 2, + :VERMILLION => 3, + :LAVENDER => 4, + :CELADON => 5, + :FUCHSIA => 6, + :SAFFRON => 7, + :CINNABAR => 8, + :LEAGUE => 9, + :VIOLET => 10, + :AZALEA => 11, + :GOLDENROD => 12, + :ECRUTEAK => 13, + :MAHOGANY => 14, + :BLACKTHORN => 15, + :OLIVINE => 16, + :CIANWOOD => 17, + :KNOTISLAND => 18, + :BOONISLAND => 19, + :KINISLAND => 20, + :CHRONOISLAND => 21, + :CRIMSON => 22, + } + return current_city_numerical[city_sym] +end + +POKEMART_MAP_ID = 357 +POKEMART_DOOR_POS = [12, 12] +# city -> Symbol +def enter_pokemart(city) + pbSet(VAR_CURRENT_MART, city) + pbSet(VAR_CURRENT_CITY_NUMERICAL_ID, get_city_numerical_id(city)) + echoln get_city_numerical_id(city) + pbFadeOutIn { + $game_temp.player_new_map_id = POKEMART_MAP_ID + $game_temp.player_new_x = POKEMART_DOOR_POS[0] + $game_temp.player_new_y = POKEMART_DOOR_POS[1] + $scene.transfer_player(true) + $game_map.autoplay + $game_map.refresh + } +end + +def exit_pokemart() + pokemart_entrances = { + :PEWTER => [380, 43, 24], + :CERULEAN => [1, 24, 22], + :VERMILLION => [19, 32, 13], + :LAVENDER => [50, 20, 23], + :CELADON => [95, 18, 15], # not a real pokemart + :FUCHSIA => [472, 7, 17], + :SAFFRON => [108, 53, 24], + :CINNABAR => [98, 30, 30], + :CRIMSON => [167, 21, 36], + :GOLDENROD => [237, 36, 33], # not a real pokemart + :AZALEA => [278, 34, 17], + :AZALEA_FLOODED => [338, 34, 17], + :VIOLET => [230, 20, 31], + :BLACKTHORN => [329, 16, 36], + :MAHOGANY => [631, 19, 19], # not a real pokemart + :ECRUTEAK => [359, 46, 38], + :OLIVINE => [138, 33, 23], + :CIANWOOD => [709.8, 46], + } + current_city = pbGet(VAR_CURRENT_MART) + current_city = :PEWTER if !current_city.is_a?(Symbol) + + entrance_map = pokemart_entrances[current_city][0] + entrance_x = pokemart_entrances[current_city][1] + entrance_y = pokemart_entrances[current_city][2] + + pbSet(VAR_CURRENT_CITY_NUMERICAL_ID, 0) + pbSet(VAR_CURRENT_MART, 0) + pbFadeOutIn { + $game_temp.player_new_map_id = entrance_map + $game_temp.player_new_x = entrance_x + $game_temp.player_new_y = entrance_y + $scene.transfer_player(true) + $game_map.autoplay + $game_map.refresh + } +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/EventUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/EventUtils.rb new file mode 100644 index 000000000..4538ed00d --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/EventUtils.rb @@ -0,0 +1,38 @@ +def turnEventTowardsEvent(turning, turnedTowards) + event_x = turnedTowards.x + event_y = turnedTowards.y + if turning.x < event_x + turning.turn_right # Event is to the right of the player + elsif turning.x > event_x + turning.turn_left # Event is to the left of the player + elsif turning.y < event_y + turning.turn_down # Event is below the player + elsif turning.y > event_y + turning.turn_up # Event is above the player + end +end + + +def turnPlayerTowardsEvent(event) + event_x = event.x + event_y = event.y + if $game_player.x < event_x + $game_player.turn_right # Event is to the right of the player + elsif $game_player.x > event_x + $game_player.turn_left # Event is to the left of the player + elsif $game_player.y < event_y + $game_player.turn_down # Event is below the player + elsif $game_player.y > event_y + $game_player.turn_up # Event is above the player + end +end + +def player_near_event?(map_id, event_id, radius) + return false if map_id != $game_map.map_id + event = $game_map.events[event_id] + return false if event.nil? + dx = $game_player.x - event.x + dy = $game_player.y - event.y + distance = Math.sqrt(dx * dx + dy * dy) + return distance <= radius +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/FusionUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/FusionUtils.rb new file mode 100644 index 000000000..bcfc838e5 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/FusionUtils.rb @@ -0,0 +1,6 @@ +def has_species_or_fusion?(species, form = -1) + return $Trainer.pokemon_party.any? { |p| p && p.isSpecies?(species) || p.isFusionOf(species) } +end + +# frozen_string_literal: true + diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GameplayUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GameplayUtils.rb new file mode 100644 index 000000000..70a870f5f --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GameplayUtils.rb @@ -0,0 +1,563 @@ +def getAllCurrentlyRoamingPokemon + currently_roaming = [] + Settings::ROAMING_SPECIES.each_with_index do |data, i| + next if !GameData::Species.exists?(data[0]) + next if data[2] > 0 && !$game_switches[data[2]] # Isn't roaming + next if $PokemonGlobal.roamPokemon[i] == true # Roaming Pokémon has been caught + currently_roaming << i + end + return currently_roaming +end + +def track_pokemon() + currently_roaming = getAllCurrentlyRoamingPokemon() + echoln currently_roaming + weather_data = [] + mapinfos = $RPGVX ? load_data("Data/MapInfos.rvdata") : load_data("Data/MapInfos.rxdata") + currently_roaming.each do |roamer_id| + map_id = $PokemonGlobal.roamPosition[roamer_id] + map_name = mapinfos[map_id].name + weather_type = Settings::ROAMING_SPECIES[roamer_id][6] + case weather_type + when :Storm + forecast_msg = _INTL("An unusual \\c[6]thunderstorm\\c[0] has been detected around \\c[6]{1}", map_name) + when :StrongWinds + forecast_msg = _INTL("Unusually \\c[9]strong winds\\c[0] have been detected around \\c[9]{1}", map_name) + when :Sunny + forecast_msg = _INTL("Unusually \\c[10]harsh sunlight\\c[0] has been detected around \\c[10]{1}", map_name) + end + weather_data << forecast_msg if forecast_msg && !weather_data.include?(forecast_msg) + end + weather_data << _INTL("No unusual weather patterns have been detected.") if weather_data.empty? + weather_data.each do |message| + Kernel.pbMessage(message) + end +end +# frozen_string_literal: true + +def getHiddenPowerName(pokemon) + hiddenpower = pbHiddenPower(pokemon) + hiddenPowerType = hiddenpower[0] + + echoln hiddenPowerType + if Settings::TRIPLE_TYPES.include?(hiddenPowerType) + return "Neutral" + end + return PBTypes.getName(hiddenPowerType) +end + +# Returns if the current map is an outdoor map +def isOutdoor() + current_map = $game_map.map_id + map_metadata = GameData::MapMetadata.try_get(current_map) + return map_metadata && map_metadata.outdoor_map +end + +def qmarkMaskCheck() + if $Trainer.seen_qmarks_sprite + unless hasHat?(HAT_QMARKS) + obtainHat(HAT_QMARKS) + obtainClothes(CLOTHES_GLITCH) + end + end +end + +def giveJigglypuffScribbles(possible_versions = [1,2,3,4]) + selected_scribbles_version = possible_versions.sample + case selected_scribbles_version + when 1 + scribbles_id= HAT_SCRIBBLES1 + when 2 + scribbles_id= HAT_SCRIBBLES2 + when 3 + scribbles_id= HAT_SCRIBBLES3 + when 4 + scribbles_id= HAT_SCRIBBLES4 + end + return if !scribbles_id + + if !hasHat?(scribbles_id) + $Trainer.unlocked_hats << scribbles_id + end + putOnHat(scribbles_id,true,true) +end + + +# chance: out of 100 +def lilypadEncounter(pokemon, minLevel, maxLevel, chance = 10) + minLevel, maxLevel = [minLevel, maxLevel].minmax + level = rand(minLevel..maxLevel) + + event = $game_map.events[@event_id] + return if !event + if rand(0..100) <= chance + pbWildBattle(pokemon, level) + else + playAnimation(Settings::GRASS_ANIMATION_ID, event.x, event.y) + end + event.erase +end + + +def calculate_pokemon_weight(pokemon, nerf = 0) + + base_weight = pokemon.weight + ivs = [] + pokemon.iv.each { |iv| + ivs << iv[1] + } + level = pokemon.level + # Ensure IVs is an array of 6 values and level is between 1 and 100 + raise "IVs array must have 6 values" if ivs.length != 6 + raise "Level must be between 1 and 100" unless (1..100).include?(level) + + # Calculate the IV Factor + iv_sum = ivs.sum + iv_factor = (iv_sum.to_f / 186) * 30 * 10 + + # Calculate the Level Factor + level_factor = (level.to_f / 100) * 5 * 10 + + # Calculate the weight + weight = base_weight * (1 + (iv_factor / 100) + (level_factor / 100)) + weight -= base_weight + # Enforce the weight variation limits + max_weight = base_weight * 4.00 # 400% increase + min_weight = base_weight * 0.5 # 50% decrease + + # Cap the weight between min and max values + weight = [[weight, min_weight].max, max_weight].min + weight -= nerf if weight - nerf > min_weight + return weight.round(2) # Round to 2 decimal places +end + +# nerf: remove x kg from each generated pokemon +def generate_weight_contest_entries(species, level, resultsVariable, nerf = 0) + # echoln "Generating Pokemon" + pokemon1 = pbGenerateWildPokemon(species, level) # Pokemon.new(species,level) + pokemon2 = pbGenerateWildPokemon(species, level) # Pokemon.new(species,level) + new_weights = [] + new_weights << calculate_pokemon_weight(pokemon1, nerf) + new_weights << calculate_pokemon_weight(pokemon2, nerf) + echoln new_weights + echoln "(nerfed by -#{nerf})" + pbSet(resultsVariable, new_weights.max) +end + + +# time in seconds +def idleHatEvent(hatId, time, switchToActivate = nil) + map = $game_map.map_id + i = 0 + while i < (time / 5) do + # /5 because we update 5 times per second + return if $game_map.map_id != map + i += 1 + pbWait(4) + i = 0 if $game_player.moving? + echoln i + end + $game_switches[switchToActivate] = true if switchToActivate + obtainHat(hatId) +end + + + +def obtainStarter(starterIndex = 0) + if ($game_switches[SWITCH_RANDOM_STARTERS]) + starter = obtainRandomizedStarter(starterIndex) + else + startersList = Settings::KANTO_STARTERS + if $game_switches[SWITCH_JOHTO_STARTERS] + startersList = Settings::JOHTO_STARTERS + elsif $game_switches[SWITCH_HOENN_STARTERS] + startersList = Settings::HOENN_STARTERS + elsif $game_switches[SWITCH_SINNOH_STARTERS] + startersList = Settings::SINNOH_STARTERS + elsif $game_switches[SWITCH_KALOS_STARTERS] + startersList = Settings::KALOS_STARTERS + end + starter = startersList[starterIndex] + end + return GameData::Species.get(starter) +end + +def isPostgame?() + return $game_switches[SWITCH_BEAT_THE_LEAGUE] +end + +def constellation_add_star(pokemon) + star_variables = get_constellation_variable(pokemon) + + pbSEPlay("GUI trainer card open", 80) + nb_stars = pbGet(star_variables) + pbSet(star_variables, nb_stars + 1) +end + + +def get_constellation_variable(pokemon) + case pokemon + when :IVYSAUR; + return VAR_CONSTELLATION_IVYSAUR + when :WARTORTLE; + return VAR_CONSTELLATION_WARTORTLE + when :ARCANINE; + return VAR_CONSTELLATION_ARCANINE + when :MACHOKE; + return VAR_CONSTELLATION_MACHOKE + when :RAPIDASH; + return VAR_CONSTELLATION_RAPIDASH + when :GYARADOS; + return VAR_CONSTELLATION_GYARADOS + when :ARTICUNO; + return VAR_CONSTELLATION_ARTICUNO + when :MEW; + return VAR_CONSTELLATION_MEW + # when :POLITOED; return VAR_CONSTELLATION_POLITOED + # when :URSARING; return VAR_CONSTELLATION_URSARING + # when :LUGIA; return VAR_CONSTELLATION_LUGIA + # when :HOOH; return VAR_CONSTELLATION_HOOH + # when :CELEBI; return VAR_CONSTELLATION_CELEBI + # when :SLAKING; return VAR_CONSTELLATION_SLAKING + # when :JIRACHI; return VAR_CONSTELLATION_JIRACHI + # when :TYRANTRUM; return VAR_CONSTELLATION_TYRANTRUM + # when :SHARPEDO; return VAR_CONSTELLATION_SHARPEDO + # when :ARCEUS; return VAR_CONSTELLATION_ARCEUS + end +end + + +def getNextLunarFeatherHint() + nb_feathers = pbGet(VAR_LUNAR_FEATHERS) + case nb_feathers + when 0 + return "Find the first feather in the northernmost dwelling in the port of exquisite sunsets..." + when 1 + return "Amidst a nursery for Pokémon youngsters, the second feather hides, surrounded by innocence." + when 2 + return "Find the next one in the inn where water meets rest" + when 3 + return "Find the next one inside the lone house in the city at the edge of civilization." + when 4 + return "The final feather lies back in the refuge for orphaned Pokémon..." + else + return "Lie in the bed... Bring me the feathers..." + end +end + +def apply_concert_lighting(light, duration = 1) + tone = Tone.new(0, 0, 0) + case light + when :GUITAR_HIT + tone = Tone.new(-50, -100, -50) + when :VERSE_1 + tone = Tone.new(-90, -110, -50) + when :VERSE_2_LIGHT + tone = Tone.new(-40, -80, -30) + when :VERSE_2_DIM + tone = Tone.new(-60, -100, -50) + when :CHORUS_1 + tone = Tone.new(0, -80, -50) + when :CHORUS_2 + tone = Tone.new(0, -50, -80) + when :CHORUS_3 + tone = Tone.new(0, -80, -80) + when :CHORUS_END + tone = Tone.new(-68, 0, -102) + when :MELOETTA_1 + tone = Tone.new(-60, -50, 20) + end + $game_screen.start_tone_change(tone, duration) +end + +def playMeloettaBandMusic() + unlocked_members = [] + unlocked_members << :DRUM if $game_switches[SWITCH_BAND_DRUMMER] + unlocked_members << :AGUITAR if $game_switches[SWITCH_BAND_ACOUSTIC_GUITAR] + unlocked_members << :EGUITAR if $game_switches[SWITCH_BAND_ELECTRIC_GUITAR] + unlocked_members << :FLUTE if $game_switches[SWITCH_BAND_FLUTE] + unlocked_members << :HARP if $game_switches[SWITCH_BAND_HARP] + + echoln unlocked_members + echoln (unlocked_members & [:DRUM, :AGUITAR, :EGUITAR, :FLUTE, :HARP]) + + track = "band/band_1" + if unlocked_members == [:DRUM, :AGUITAR, :EGUITAR, :FLUTE, :HARP] + track = "band/band_full" + else + if unlocked_members.include?(:FLUTE) + track = "band/band_5a" + elsif unlocked_members.include?(:HARP) + track = "band/band_5b" + else + if unlocked_members.include?(:EGUITAR) && unlocked_members.include?(:AGUITAR) + track = "band/band_4" + elsif unlocked_members.include?(:AGUITAR) + track = "band/band_3a" + elsif unlocked_members.include?(:EGUITAR) + track = "band/band_3b" + elsif unlocked_members.include?(:DRUM) + track = "band/band_2" + end + end + end + echoln track + pbBGMPlay(track) +end + +def regirock_steel_move_boulder() + + switches_position = [ + [16, 21], [18, 21], [20, 21], [22, 21], + [16, 23], [22, 23], + [16, 25], [18, 25], [20, 25], [22, 25] + ] + boulder_event = get_self + old_x = boulder_event.x + old_y = boulder_event.y + stepped_off_switch = switches_position.find { |position| position[0] == old_x && position[1] == old_y } + + pbPushThisBoulder() + boulder_event = get_self + + if stepped_off_switch + switch_event = $game_map.get_event_at_position(old_x, old_y, [boulder_event.id]) + echoln switch_event.id if switch_event + pbSEPlay("Entering Door", nil, 80) + pbSetSelfSwitch(switch_event.id, "A", false) if switch_event + end + + stepped_on_switch = switches_position.find { |position| position[0] == boulder_event.x && position[1] == boulder_event.y } + if stepped_on_switch + switch_event = $game_map.get_event_at_position(boulder_event.x, boulder_event.y, [boulder_event.id]) + echoln switch_event.id if switch_event + pbSEPlay("Entering Door") + pbSetSelfSwitch(switch_event.id, "A", true) if switch_event + end +end + + +KANTO_DARKNESS_STAGE_1 = [ + 50, # Lavender town + 409, # Route 8 + 351, # Route 9 (east) + 495, # Route 9 (west) + 154, # Route 10 + 108, # Saffron city + 1, # Cerulean City + 387, # Cerulean City (race) + 106, # Route 4 + 8, # Route 24 + 9, # Route 25 + 400, # Pokemon Tower + 401, # Pokemon Tower + 402, # Pokemon Tower + 403, # Pokemon Tower + 467, # Pokemon Tower + 468, # Pokemon Tower + 469, # Pokemon Tower + 159, # Route 12 + 349, # Rock tunnel + 350, # Rock tunnel + 512, # Rock tunnel (outdoor) + 12, # Route 5 + +] +KANTO_DARKNESS_STAGE_2 = [ + 95, # Celadon city + 436, # Celadon city dept store (roof) + 143, # Route 23 + 167, # Crimson city + 413, # Route 7 + 438, # Route 16 + 146, # Route 17 + 106, # Route 4 + 19, # Vermillion City + 36, # S.S. Anne deck + 16, # Route 6 + 437, # Route 13 + 155, # Route 11 + 140, # Diglett cave + 398, # Diglett cave + 399, # Diglett cave +] +KANTO_DARKNESS_STAGE_3 = [ + 472, # Fuchsia city + 445, # Safari Zone 1 + 484, # Safari Zone 2 + 485, # Safari Zone 3 + 486, # Safari Zone 4 + 487, # Safari Zone 5 + 444, # Route 15 + 440, # Route 14 + 712, # Creepy house + 517, # Route 18 + 57, # Route 19 + 227, # Route 19 (underwater) + 56, # Route 19 (surf race) + 58, # Route 20 + 480, # Route 20 underwater 1 + 228, # Route 20 underwater 2 + 98, # Cinnabar island + 58, # Route 21 + 827, # Mt. Moon summit +] +KANTO_DARKNESS_STAGE_4 = KANTO_OUTDOOR_MAPS + +def darknessEffectOnCurrentMap() + return if !$game_switches + return if !$game_switches[SWITCH_KANTO_DARKNESS] + return darknessEffectOnMap($game_map.map_id) +end + +def darknessEffectOnMap(map_id) + return if !$game_switches + return if !$game_switches[SWITCH_KANTO_DARKNESS] + return if !KANTO_OUTDOOR_MAPS.include?(map_id) + dark_maps = [] + dark_maps += KANTO_DARKNESS_STAGE_1 if $game_switches[SWITCH_KANTO_DARKNESS_STAGE_1] + dark_maps += KANTO_DARKNESS_STAGE_2 if $game_switches[SWITCH_KANTO_DARKNESS_STAGE_2] + dark_maps += KANTO_DARKNESS_STAGE_3 if $game_switches[SWITCH_KANTO_DARKNESS_STAGE_3] + dark_maps = KANTO_OUTDOOR_MAPS if $game_switches[SWITCH_KANTO_DARKNESS_STAGE_4] + return dark_maps.include?(map_id) +end + +def apply_darkness() + $PokemonTemp.darknessSprite = DarknessSprite.new + darkness = $PokemonTemp.darknessSprite + darkness.radius = 276 + while darkness.radius > 64 + Graphics.update + Input.update + pbUpdateSceneMap + darkness.radius -= 4 + end + $PokemonGlobal.flashUsed = false + $PokemonTemp.darknessSprite.dispose + Events.onMapSceneChange.trigger(self, $scene, true) +end + +def isInMtMoon() + mt_moon_maps = [102, 103, 105, 496, 104] + return mt_moon_maps.include?($game_map.map_id) +end + +def getMtMoonDirection() + maps_east = [380, # Pewter city + 490, # Route 3 + 303, # indigo plateau + 145, # Route 26 + 147, # Route 27 + ] + maps_south = [ + 8, # Route 24 + 9, # Route 25 + 143, # Route 23 + 167, # Crimson city + ] + maps_west = [ + 106, # route 4 + 1, # cerulean + 495, # route 9 + 351, # route 9 + 10 # cerulean cape + ] + return 2 if maps_south.include?($game_map.map_id) + return 4 if maps_west.include?($game_map.map_id) + return 6 if maps_east.include?($game_map.map_id) + return 8 # north (most maps) +end + + + +def Kernel.setRocketPassword(variableNum) + abilityIndex = rand(233) + speciesIndex = rand(PBSpecies.maxValue - 1) + + word1 = PBSpecies.getName(speciesIndex) + word2 = GameData::Ability.get(abilityIndex).name + password = _INTL("{1}'s {2}", word1, word2) + pbSet(variableNum, password) +end + +def obtainBadgeMessage(badgeName) + Kernel.pbMessage(_INTL("\\me[Badge get]{1} obtained the {2}!", $Trainer.name, badgeName)) +end + + +def getFossilsGuyTeam(level) + base_poke_evolution_level = 20 + fossils_evolution_level_1 = 30 + fossils_evolution_level_2 = 50 + + fossils = [] + base_poke = level <= base_poke_evolution_level ? :B88H109 : :B89H110 + team = [] + team << Pokemon.new(base_poke, level) + + # Mt. Moon fossil + if $game_switches[SWITCH_PICKED_HELIC_FOSSIL] + fossils << :KABUTO if level < fossils_evolution_level_1 + fossils << :KABUTOPS if level >= fossils_evolution_level_1 + elsif $game_switches[SWITCH_PICKED_DOME_FOSSIL] + fossils << :OMANYTE if level < fossils_evolution_level_1 + fossils << :OMASTAR if level >= fossils_evolution_level_1 + end + + # S.S. Anne fossil + if $game_switches[SWITCH_PICKED_LILEEP_FOSSIL] + fossils << :ANORITH if level < fossils_evolution_level_1 + fossils << :ARMALDO if level >= fossils_evolution_level_1 + + elsif $game_switches[SWITCH_PICKED_ANORITH_FOSSIL] + fossils << :LILEEP if level < fossils_evolution_level_1 + fossils << :CRADILY if level >= fossils_evolution_level_1 + end + # Celadon fossil + if $game_switches[SWITCH_PICKED_ARMOR_FOSSIL] + fossils << :CRANIDOS if level < fossils_evolution_level_2 + fossils << :RAMPARDOS if level >= fossils_evolution_level_2 + + elsif $game_switches[SWITCH_PICKED_SKULL_FOSSIL] + fossils << :SHIELDON if level < fossils_evolution_level_2 + fossils << :BASTIODON if level >= fossils_evolution_level_2 + end + + skip_next = false + for index in 0..fossils.length + if index == fossils.length - 1 + team << Pokemon.new(fossils[index], level) + else + if skip_next + skip_next = false + next + end + head_poke = fossils[index] + body_poke = fossils[index + 1] + if head_poke && body_poke + newPoke = getFusionSpecies(dexNum(body_poke), dexNum(head_poke)) + team << Pokemon.new(newPoke, level) + skip_next = true + end + end + end + return team +end + +# tradedPoke = pbGet(154) +# party=[tradedPoke] +# customTrainerBattle("Eusine", +# :MYSTICALMAN, +# party, +# tradedPoke.level, +# "Okay, okay I'll give it back!" ) +def fossilsGuyBattle(level = 20, end_message = "") + team = getFossilsGuyTeam(level) + customTrainerBattle("Miguel", + :SUPERNERD, + team, + level, + end_message + ) + +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GraphicsUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GraphicsUtils.rb new file mode 100644 index 000000000..fddde7f56 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/GraphicsUtils.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +def addWaterCausticsEffect(fog_name = "caustic1", opacity = 16) + $game_map.fog_name = fog_name + $game_map.fog_hue = 0 + $game_map.fog_opacity = opacity + #$game_map.fog_blend_type = @parameters[4] + $game_map.fog_zoom = 200 + $game_map.fog_sx = 2 + $game_map.fog_sy = 2 + + $game_map.setFog2(fog_name, -3, 0, opacity,) +end + +def stopWaterCausticsEffect() + $game_map.fog_opacity = 0 + $game_map.eraseFog2() +end + +def clear_all_images() + for i in 1..99 + # echoln i.to_s + " : " + $game_screen.pictures[i].name + $game_screen.pictures[i].erase + end +end + + +def playPokeFluteAnimation + # return if $Trainer.outfit != 0 + # $game_player.setDefaultCharName("players/pokeflute", 0, false) + # Graphics.update + # Input.update + # pbUpdateSceneMap +end + +def restoreDefaultCharacterSprite(charset_number = 0) + meta = GameData::Metadata.get_player($Trainer.character_ID) + $game_player.setDefaultCharName(nil, 0, false) + $game_player.character_name = meta[1] + Graphics.update + Input.update + pbUpdateSceneMap +end + +# if need to play animation from event route +def playAnimation(animationId, x, y) + return if !$scene.is_a?(Scene_Map) + $scene.spriteset.addUserAnimation(animationId, x, y, true) +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/MenuUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/MenuUtils.rb new file mode 100644 index 000000000..7ed9b253e --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/MenuUtils.rb @@ -0,0 +1,167 @@ +def optionsMenu(options = [], cmdIfCancel = -1, startingOption = 0) + cmdIfCancel = -1 if !cmdIfCancel + result = pbShowCommands(nil, options, cmdIfCancel, startingOption) + echoln "menuResult :#{result}" + return result +end + +def displaySpriteWindowWithMessage(pif_sprite, message = "", x = 0, y = 0, z = 0) + spriteLoader = BattleSpriteLoader.new + sprite_bitmap = spriteLoader.load_pif_sprite_directly(pif_sprite) + pictureWindow = PictureWindow.new(sprite_bitmap.bitmap) + + pictureWindow.opacity = 0 + pictureWindow.z = z + pictureWindow.x = x + pictureWindow.y = y + pbMessage(message) + pictureWindow.dispose +end + +def select_any_pokemon() + commands = [] + for dex_num in 1..NB_POKEMON + species = getPokemon(dex_num) + commands.push([dex_num - 1, species.real_name, species.id]) + end + return pbChooseList(commands, 0, nil, 1) +end + +def purchaseDyeKitMenu(hats_kit_price=0,clothes_kit_price=0) + + commands = [] + command_hats = "Hats Dye Kit ($#{hats_kit_price})" + command_clothes = "Clothes Dye Kit ($#{clothes_kit_price})" + command_cancel = "Cancel" + + commands << command_hats if !$PokemonBag.pbHasItem?(:HATSDYEKIT) + commands << command_clothes if !$PokemonBag.pbHasItem?(:CLOTHESDYEKIT) + commands << command_cancel + + if commands.length <= 1 + pbCallBub(2,@event_id) + pbMessage("\\C[1]Dye Kits\\C[0] can be used to dye clothes all sorts of colours!") + + pbCallBub(2,@event_id) + pbMessage("You can use them at any time when you change clothes.") + return + end + pbCallBub(2,@event_id) + pbMessage("\\GWelcome! Are you interested in dyeing your outfits different colours?") + + pbCallBub(2,@event_id) + pbMessage("I make handy \\C[1]Dye Kits\\C[0] from my Smeargle's paint that can be used to dye your outfits any color you want!") + + pbCallBub(2,@event_id) + pbMessage("\\GWhat's more is that it's reusable so you can go completely wild with it if you want! Are you interested?") + + choice = optionsMenu(commands,commands.length) + case commands[choice] + when command_hats + if $Trainer.money < hats_kit_price + pbCallBub(2,@event_id) + pbMessage("Oh, you don't have enough money...") + return + end + pbMessage("\\G\\PN purchased the dye kit.") + $Trainer.money -= hats_kit_price + pbSEPlay("SlotsCoin") + Kernel.pbReceiveItem(:HATSDYEKIT) + pbCallBub(2,@event_id) + pbMessage("\\GHere you go! Have fun dyeing your hats!") + when command_clothes + if $Trainer.money < clothes_kit_price + pbCallBub(2,@event_id) + pbMessage("Oh, you don't have enough money...") + return + end + pbMessage("\\G\\PN purchased the dye kit.") + $Trainer.money -= clothes_kit_price + pbSEPlay("SlotsCoin") + Kernel.pbReceiveItem(:CLOTHESDYEKIT) + pbCallBub(2,@event_id) + pbMessage("\\GHere you go! Have fun dyeing your clothes!") + end + pbCallBub(2,@event_id) + pbMessage("You can use \\C[1]Dye Kits\\C[0] at any time when you change clothes.") +end + + +def promptCaughtPokemonAction(pokemon) + pickedOption = false + return pbStorePokemon(pokemon) if !$Trainer.party_full? + return promptKeepOrRelease(pokemon) if isOnPinkanIsland() && !$game_switches[SWITCH_PINKAN_FINISHED] + while !pickedOption + command = pbMessage(_INTL("\\ts[]Your team is full!"), + [_INTL("Add to your party"), _INTL("Store to PC"),], 2) + echoln ("command " + command.to_s) + case command + when 0 # SWAP + if swapCaughtPokemon(pokemon) + echoln pickedOption + pickedOption = true + end + else + # STORE + pbStorePokemon(pokemon) + echoln pickedOption + pickedOption = true + end + end + +end + +def promptKeepOrRelease(pokemon) + pickedOption = false + while !pickedOption + command = pbMessage(_INTL("\\ts[]Your team is full!"), + [_INTL("Release a party member"), _INTL("Release this #{pokemon.name}"),], 2) + echoln ("command " + command.to_s) + case command + when 0 # SWAP + if swapReleaseCaughtPokemon(pokemon) + pickedOption = true + end + else + pickedOption = true + end + end +end + +# def pbChoosePokemon(variableNumber, nameVarNumber, ableProc = nil, allowIneligible = false) +def swapCaughtPokemon(caughtPokemon) + pbChoosePokemon(1, 2, + proc { |poke| + !poke.egg? && + !(poke.isShadow? rescue false) + }) + index = pbGet(1) + return false if index == -1 + $PokemonStorage.pbStoreCaught($Trainer.party[index]) + pbRemovePokemonAt(index) + pbStorePokemon(caughtPokemon) + + tmp = $Trainer.party[index] + $Trainer.party[index] = $Trainer.party[-1] + $Trainer.party[-1] = tmp + return true +end + +def swapReleaseCaughtPokemon(caughtPokemon) + pbChoosePokemon(1, 2, + proc { |poke| + !poke.egg? && + !(poke.isShadow? rescue false) + }) + index = pbGet(1) + return false if index == -1 + releasedPokemon = $Trainer.party[index] + pbMessage("#{releasedPokemon.name} was released.") + pbRemovePokemonAt(index) + pbStorePokemon(caughtPokemon) + + tmp = $Trainer.party[index] + $Trainer.party[index] = $Trainer.party[-1] + $Trainer.party[-1] = tmp + return true +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/OutfitUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/OutfitUtils.rb new file mode 100644 index 000000000..a76bb93d8 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/OutfitUtils.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +def unlock_easter_egg_hats() + if $Trainer.name == "Ash" + $Trainer.hat = HAT_ASH + $Trainer.unlock_hat(HAT_ASH) + end + if $Trainer.name == "Frogman" + $Trainer.hat = HAT_FROG + $Trainer.unlock_hat(HAT_FROG) + end +end + +def setupStartingOutfit() + $Trainer.hat = nil + $Trainer.clothes = STARTING_OUTFIT + unlock_easter_egg_hats() + gender = pbGet(VAR_TRAINER_GENDER) + if gender == GENDER_FEMALE + $Trainer.unlock_clothes(DEFAULT_OUTFIT_FEMALE, true) + $Trainer.unlock_hat(DEFAULT_OUTFIT_FEMALE, true) + $Trainer.hair = "3_" + DEFAULT_OUTFIT_FEMALE if !$Trainer.hair # when migrating old savefiles + + elsif gender == GENDER_MALE + $Trainer.unlock_clothes(DEFAULT_OUTFIT_MALE, true) + $Trainer.unlock_hat(DEFAULT_OUTFIT_MALE, true) + + echoln $Trainer.hair + $Trainer.hair = ("3_" + DEFAULT_OUTFIT_MALE) if !$Trainer.hair # when migrating old savefiles + echoln $Trainer.hair + end + $Trainer.unlock_hair(DEFAULT_OUTFIT_MALE, true) + $Trainer.unlock_hair(DEFAULT_OUTFIT_FEMALE, true) + $Trainer.unlock_clothes(STARTING_OUTFIT, true) +end + +def give_date_specific_hats() + current_date = Time.new + # Christmas + if (current_date.day == 24 || current_date.day == 25) && current_date.month == 12 + if !$Trainer.unlocked_hats.include?(HAT_SANTA) + pbCallBub(2, @event_id, true) + pbMessage("Hi! We're giving out a special hat today for the holidays season. Enjoy!") + obtainHat(HAT_SANTA) + end + end + + # April's fool + if (current_date.day == 1 && current_date.month == 4) + if !$Trainer.unlocked_hats.include?(HAT_CLOWN) + pbCallBub(2, @event_id, true) + pbMessage("Hi! We're giving out this fun accessory for this special day. Enjoy!") + obtainHat(HAT_CLOWN) + end + end +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PlayerUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PlayerUtils.rb new file mode 100644 index 000000000..0b4aa7f5d --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PlayerUtils.rb @@ -0,0 +1,8 @@ +def isPlayerMale() + return pbGet(VAR_TRAINER_GENDER) == GENDER_MALE +end + +def isPlayerFemale() + return pbGet(VAR_TRAINER_GENDER) == GENDER_FEMALE +end# frozen_string_literal: true + diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PokemonUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PokemonUtils.rb new file mode 100644 index 000000000..67214e851 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/PokemonUtils.rb @@ -0,0 +1,247 @@ + +def replaceFusionSpecies(pokemon, speciesToChange, newSpecies) + currentBody = pokemon.species_data.get_body_species_symbol() + currentHead = pokemon.species_data.get_head_species_symbol() + should_update_body = currentBody == speciesToChange + should_update_head = currentHead == speciesToChange + + echoln speciesToChange + echoln currentBody + echoln currentHead + + return if !should_update_body && !should_update_head + + newSpeciesBody = should_update_body ? newSpecies : currentBody + newSpeciesHead = should_update_head ? newSpecies : currentHead + + newSpecies = getFusionSpecies(newSpeciesBody, newSpeciesHead) + echoln newSpecies.id_number + pokemon.species = newSpecies +end + +def changeSpeciesSpecific(pokemon, newSpecies) + pokemon.species = newSpecies + $Trainer.pokedex.set_seen(newSpecies) + $Trainer.pokedex.set_owned(newSpecies) +end + + +def setPokemonMoves(pokemon, move_ids = []) + moves = [] + move_ids.each { |move_id| + moves << Pokemon::Move.new(move_id) + } + pokemon.moves = moves +end + + +def getGenericPokemonCryText(pokemonSpecies) + case pokemonSpecies + when 25 + return "Pika!" + when 16, 17, 18, 21, 22, 144, 145, 146, 227, 417, 418, 372 # birds + return "Squawk!" + when 163, 164 + return "Hoot!" # owl + else + return "Guaugh!" + end +end + + +def Kernel.getPlateType(item) + return :FIGHTING if item == PBItems::FISTPLATE + return :FLYING if item == PBItems::SKYPLATE + return :POISON if item == PBItems::TOXICPLATE + return :GROUND if item == PBItems::EARTHPLATE + return :ROCK if item == PBItems::STONEPLATE + return :BUG if item == PBItems::INSECTPLATE + return :GHOST if item == PBItems::SPOOKYPLATE + return :STEEL if item == PBItems::IRONPLATE + return :FIRE if item == PBItems::FLAMEPLATE + return :WATER if item == PBItems::SPLASHPLATE + return :GRASS if item == PBItems::MEADOWPLATE + return :ELECTRIC if item == PBItems::ZAPPLATE + return :PSYCHIC if item == PBItems::MINDPLATE + return :ICE if item == PBItems::ICICLEPLATE + return :DRAGON if item == PBItems::DRACOPLATE + return :DARK if item == PBItems::DREADPLATE + return :FAIRY if item == PBItems::PIXIEPLATE + return -1 +end + +def Kernel.listPlatesInBag() + list = [] + list << PBItems::FISTPLATE if $PokemonBag.pbQuantity(:FISTPLATE) >= 1 + list << PBItems::SKYPLATE if $PokemonBag.pbQuantity(:SKYPLATE) >= 1 + list << PBItems::TOXICPLATE if $PokemonBag.pbQuantity(:TOXICPLATE) >= 1 + list << PBItems::EARTHPLATE if $PokemonBag.pbQuantity(:EARTHPLATE) >= 1 + list << PBItems::STONEPLATE if $PokemonBag.pbQuantity(:STONEPLATE) >= 1 + list << PBItems::INSECTPLATE if $PokemonBag.pbQuantity(:INSECTPLATE) >= 1 + list << PBItems::SPOOKYPLATE if $PokemonBag.pbQuantity(:SPOOKYPLATE) >= 1 + list << PBItems::IRONPLATE if $PokemonBag.pbQuantity(:IRONPLATE) >= 1 + list << PBItems::FLAMEPLATE if $PokemonBag.pbQuantity(:FLAMEPLATE) >= 1 + list << PBItems::SPLASHPLATE if $PokemonBag.pbQuantity(:SPLASHPLATE) >= 1 + list << PBItems::MEADOWPLATE if $PokemonBag.pbQuantity(:MEADOWPLATE) >= 1 + list << PBItems::ZAPPLATE if $PokemonBag.pbQuantity(:ZAPPLATE) >= 1 + list << PBItems::MINDPLATE if $PokemonBag.pbQuantity(:MINDPLATE) >= 1 + list << PBItems::ICICLEPLATE if $PokemonBag.pbQuantity(:ICICLEPLATE) >= 1 + list << PBItems::DRACOPLATE if $PokemonBag.pbQuantity(:DRACOPLATE) >= 1 + list << PBItems::DREADPLATE if $PokemonBag.pbQuantity(:DREADPLATE) >= 1 + list << PBItems::PIXIEPLATE if $PokemonBag.pbQuantity(:PIXIEPLATE) >= 1 + return list +end + +def getArceusPlateType(heldItem) + return :NORMAL if heldItem == nil + case heldItem + when :FISTPLATE + return :FIGHTING + when :SKYPLATE + return :FLYING + when :TOXICPLATE + return :POISON + when :EARTHPLATE + return :GROUND + when :STONEPLATE + return :ROCK + when :INSECTPLATE + return :BUG + when :SPOOKYPLATE + return :GHOST + when :IRONPLATE + return :STEEL + when :FLAMEPLATE + return :FIRE + when :SPLASHPLATE + return :WATER + when :MEADOWPLATE + return :GRASS + when :ZAPPLATE + return :ELECTRIC + when :MINDPLATE + return :PSYCHIC + when :ICICLEPLATE + return :ICE + when :DRACOPLATE + return :DRAGON + when :DREADPLATE + return :DARK + when :PIXIEPLATE + return :FAIRY + else + return :NORMAL + end +end + + +def changeOricorioForm(pokemon, form = nil) + oricorio_forms = [:ORICORIO_1, :ORICORIO_2, :ORICORIO_3, :ORICORIO_4] + body_id = pokemon.isFusion? ? get_body_species_from_symbol(pokemon.species) : pokemon.species + head_id = pokemon.isFusion? ? get_head_species_from_symbol(pokemon.species) : pokemon.species + + oricorio_body = oricorio_forms.include?(body_id) + oricorio_head = oricorio_forms.include?(head_id) + + if form == 1 + body_id = :ORICORIO_1 if oricorio_body + head_id = :ORICORIO_1 if oricorio_head + elsif form == 2 + body_id = :ORICORIO_2 if oricorio_body + head_id = :ORICORIO_2 if oricorio_head + elsif form == 3 + body_id = :ORICORIO_3 if oricorio_body + head_id = :ORICORIO_3 if oricorio_head + elsif form == 4 + body_id = :ORICORIO_4 if oricorio_body + head_id = :ORICORIO_4 if oricorio_head + else + return false + end + + head_number = getDexNumberForSpecies(head_id) + body_number = getDexNumberForSpecies(body_id) + + newForm = pokemon.isFusion? ? getSpeciesIdForFusion(head_number, body_number) : head_id + $Trainer.pokedex.set_seen(newForm) + $Trainer.pokedex.set_owned(newForm) + + pokemon.species = newForm + return true +end + + +def changeOricorioFlower(form = 1) + if $PokemonGlobal.stepcount % 25 == 0 + if !hatUnlocked?(HAT_FLOWER) && rand(2) == 0 + obtainHat(HAT_FLOWER) + $PokemonGlobal.stepcount += 1 + else + pbMessage(_INTL("Woah! A Pokémon jumped out of the flower!")) + pbWildBattle(:FOMANTIS, 10) + $PokemonGlobal.stepcount += 1 + end + end + return if !($Trainer.has_species_or_fusion?(:ORICORIO_1) || $Trainer.has_species_or_fusion?(:ORICORIO_2) || $Trainer.has_species_or_fusion?(:ORICORIO_3) || $Trainer.has_species_or_fusion?(:ORICORIO_4)) + message = "" + form_name = "" + if form == 1 + message = "It's a flower with red nectar. " + form_name = "Baile" + elsif form == 2 + message = "It's a flower with yellow nectar. " + form_name = "Pom-pom" + elsif form == 3 + message = "It's a flower with pink nectar. " + form_name = "Pa'u" + elsif form == 4 + message = "It's a flower with blue nectar. " + form_name = "Sensu" + end + + message = message + "Show it to a Pokémon?" + if pbConfirmMessage(message) + pbChoosePokemon(1, 2, + proc { |poke| + !poke.egg? && + (Kernel.isPartPokemon(poke, :ORICORIO_1) || + Kernel.isPartPokemon(poke, :ORICORIO_2) || + Kernel.isPartPokemon(poke, :ORICORIO_3) || + Kernel.isPartPokemon(poke, :ORICORIO_4)) + }) + if (pbGet(1) != -1) + poke = $Trainer.party[pbGet(1)] + if changeOricorioForm(poke, form) + pbMessage(_INTL("{1} switched to the {2} style", poke.name, form_name)) + pbSet(1, poke.name) + else + pbMessage(_INTL("{1} remained the same...", poke.name, form_name)) + end + end + end +end + +def oricorioEventPickFlower(flower_color) + quest_progression = pbGet(VAR_ORICORIO_FLOWERS) + if flower_color == :PINK + if !$game_switches[SWITCH_ORICORIO_QUEST_PINK] + pbMessage(_INTL("Woah! A Pokémon jumped out of the flower!")) + pbWildBattle(:FOMANTIS, 10) + end + $game_switches[SWITCH_ORICORIO_QUEST_PINK] = true + pbMessage(_INTL("It's a flower with pink nectar.")) + pbSEPlay("MiningAllFound") + pbMessage(_INTL("{1} picked some of the pink flowers.", $Trainer.name)) + elsif flower_color == :RED && quest_progression == 1 + $game_switches[SWITCH_ORICORIO_QUEST_RED] = true + pbMessage(_INTL("It's a flower with red nectar.")) + pbSEPlay("MiningAllFound") + pbMessage(_INTL("{1} picked some of the red flowers.", $Trainer.name)) + elsif flower_color == :BLUE && quest_progression == 2 + $game_switches[SWITCH_ORICORIO_QUEST_BLUE] = true + pbMessage(_INTL("It's a flower with blue nectar.")) + pbSEPlay("MiningAllFound") + pbMessage(_INTL("{1} picked some of the blue flowers.", $Trainer.name)) + end + +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/RepairUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/RepairUtils.rb new file mode 100644 index 000000000..a5f036465 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/RepairUtils.rb @@ -0,0 +1,102 @@ +def fixMissedHMs() + # Flash + if $PokemonBag.pbQuantity(:HM08) < 1 && $PokemonGlobal.questRewardsObtained.include?(:HM08) + pbReceiveItem(:HM08) + end + + # Cut + if $PokemonBag.pbQuantity(:HM01) < 1 && $game_switches[SWITCH_SS_ANNE_DEPARTED] + pbReceiveItem(:HM01) + end + + # Strength + if $PokemonBag.pbQuantity(:HM04) < 1 && $game_switches[SWITCH_SNORLAX_GONE_ROUTE_12] + pbReceiveItem(:HM04) + end + + # Surf + if $PokemonBag.pbQuantity(:HM03) < 1 && $game_self_switches[[107, 1, "A"]] + pbReceiveItem(:HM03) + end + + # Teleport + if $PokemonBag.pbQuantity(:HM07) < 1 && $game_switches[SWITCH_TELEPORT_NPC] + pbReceiveItem(:HM07) + end + + # Fly + if $PokemonBag.pbQuantity(:HM02) < 1 && $game_self_switches[[439, 1, "B"]] + pbReceiveItem(:HM02) + end + + # Waterfall + if $PokemonBag.pbQuantity(:HM05) < 1 && $game_switches[SWITCH_GOT_WATERFALL] + pbReceiveItem(:HM05) + end + + # Dive + if $PokemonBag.pbQuantity(:HM06) < 1 && $game_switches[SWITCH_GOT_DIVE] + pbReceiveItem(:HM06) + end + + # Rock Climb + if $PokemonBag.pbQuantity(:HM10) < 1 && $game_switches[SWITCH_GOT_ROCK_CLIMB] + pbReceiveItem(:HM10) + end +end + +def fixFinishedRocketQuests() + fix_broken_TR_quests() + + var_tr_missions_cerulean = 288 + + switch_tr_mission_cerulean_4 = 1116 + switch_tr_mission_celadon_1 = 1084 + switch_tr_mission_celadon_2 = 1086 + switch_tr_mission_celadon_3 = 1088 + switch_tr_mission_celadon_4 = 1110 + switch_pinkan_done = 1119 + + nb_cerulean_missions = pbGet(var_tr_missions_cerulean) + + finishTRQuest("tr_cerulean_1", :SUCCESS, true) if nb_cerulean_missions >= 1 && !pbCompletedQuest?("tr_cerulean_1") + echoln pbCompletedQuest?("tr_cerulean_1") + finishTRQuest("tr_cerulean_2", :SUCCESS, true) if nb_cerulean_missions >= 2 && !pbCompletedQuest?("tr_cerulean_2") + finishTRQuest("tr_cerulean_3", :SUCCESS, true) if nb_cerulean_missions >= 3 && !pbCompletedQuest?("tr_cerulean_3") + finishTRQuest("tr_cerulean_4", :SUCCESS, true) if $game_switches[switch_tr_mission_cerulean_4] && !pbCompletedQuest?("tr_cerulean_4") + + finishTRQuest("tr_celadon_1", :SUCCESS, true) if $game_switches[switch_tr_mission_celadon_1] && !pbCompletedQuest?("tr_celadon_1") + finishTRQuest("tr_celadon_2", :SUCCESS, true) if $game_switches[switch_tr_mission_celadon_2] && !pbCompletedQuest?("tr_celadon_2") + finishTRQuest("tr_celadon_3", :SUCCESS, true) if $game_switches[switch_tr_mission_celadon_3] && !pbCompletedQuest?("tr_celadon_3") + finishTRQuest("tr_celadon_4", :SUCCESS, true) if $game_switches[switch_tr_mission_celadon_4] && !pbCompletedQuest?("tr_celadon_4") + + finishTRQuest("tr_pinkan", :SUCCESS, true) if $game_switches[switch_pinkan_done] && !pbCompletedQuest?("tr_pinkan") +end + +def fix_broken_TR_quests() + for trainer_quest in $Trainer.quests + if trainer_quest.id == 0 # tr quests were all set to ID 0 instead of their real ID in v 6.4.0 + for rocket_quest_id in TR_QUESTS.keys + rocket_quest = TR_QUESTS[rocket_quest_id] + next if !rocket_quest + if trainer_quest.name == rocket_quest.name + trainer_quest.id = rocket_quest_id + end + end + end + end +end + +def failAllIncompleteRocketQuests() + for trainer_quest in $Trainer.quests + finishTRQuest("tr_cerulean_1", :FAILURE) if trainer_quest.id == "tr_cerulean_1" && !pbCompletedQuest?("tr_cerulean_1") + finishTRQuest("tr_cerulean_2", :FAILURE) if trainer_quest.id == "tr_cerulean_2" && !pbCompletedQuest?("tr_cerulean_2") + finishTRQuest("tr_cerulean_3", :FAILURE) if trainer_quest.id == "tr_cerulean_3" && !pbCompletedQuest?("tr_cerulean_3") + finishTRQuest("tr_cerulean_4", :FAILURE) if trainer_quest.id == "tr_cerulean_4" && !pbCompletedQuest?("tr_cerulean_4") + + finishTRQuest("tr_celadon_1", :FAILURE) if trainer_quest.id == "tr_celadon_1" && !pbCompletedQuest?("tr_celadon_1") + finishTRQuest("tr_celadon_2", :FAILURE) if trainer_quest.id == "tr_celadon_2" && !pbCompletedQuest?("tr_celadon_2") + finishTRQuest("tr_celadon_3", :FAILURE) if trainer_quest.id == "tr_celadon_3" && !pbCompletedQuest?("tr_celadon_3") + finishTRQuest("tr_celadon_4", :FAILURE) if trainer_quest.id == "tr_celadon_4" && !pbCompletedQuest?("tr_celadon_4") + end +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SpritesUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SpritesUtils.rb new file mode 100644 index 000000000..054293d7e --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SpritesUtils.rb @@ -0,0 +1,7 @@ +#ex:Game_Event.new +# forced_sprites = {"1.133" => "a"} +# setForcedAltSprites(forced_sprites) +# +def setForcedAltSprites(forcedSprites_map) + $PokemonTemp.forced_alt_sprites = forcedSprites_map +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SystemUtils.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SystemUtils.rb new file mode 100644 index 000000000..4f5b81cb4 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/Utils/SystemUtils.rb @@ -0,0 +1,145 @@ +# frozen_string_literal: true + +# todo: implement +def getMappedKeyFor(internalKey) + + keybinding_fileName = "keybindings.mkxp1" + path = System.data_directory + keybinding_fileName + + parse_keybindings(path) + + # echoln Keybindings.new(path).bindings +end + + + +def formatNumberToString(number) + return number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse +end + +def playCry(pokemonSpeciesSymbol) + species = GameData::Species.get(pokemonSpeciesSymbol).species + GameData::Species.play_cry_from_species(species) +end + +# Get difficulty for displaying in-game +def getDisplayDifficulty + if $game_switches[SWITCH_GAME_DIFFICULTY_EASY] || $Trainer.lowest_difficulty <= 0 + return getDisplayDifficultyFromIndex(0) + elsif $Trainer.lowest_difficulty <= 1 + return getDisplayDifficultyFromIndex(1) + elsif $game_switches[SWITCH_GAME_DIFFICULTY_HARD] + return getDisplayDifficultyFromIndex(2) + else + return getDisplayDifficultyFromIndex(1) + end +end + +def getDisplayDifficultyFromIndex(difficultyIndex) + return "Easy" if difficultyIndex == 0 + return "Normal" if difficultyIndex == 1 + return "Hard" if difficultyIndex == 2 + return "???" +end + +def getGameModeFromIndex(index) + return "Classic" if index == 0 + return "Random" if index == 1 + return "Remix" if index == 2 + return "Expert" if index == 3 + return "Species" if index == 4 + return "Debug" if index == 5 + return "" +end + +def openUrlInBrowser(url = "") + begin + # Open the URL in the default web browser + system("xdg-open", url) || system("open", url) || system("start", url) + rescue + Input.clipboard = url + pbMessage("The game could not open the link in the browser") + pbMessage("The link has been copied to your clipboard instead") + end +end + +def clearAllSelfSwitches(mapID, switch = "A", newValue = false) + map = $MapFactory.getMap(mapID, false) + map.events.each { |event_array| + event_id = event_array[0] + pbSetSelfSwitch(event_id, switch, newValue, mapID) + } +end + + +def isTuesdayNight() + day = getDayOfTheWeek() + hour = pbGetTimeNow().hour + echoln hour + return (day == :TUESDAY && hour >= 20) || (day == :WEDNESDAY && hour < 5) +end + + +def setDifficulty(index) + $Trainer.selected_difficulty = index + case index + when 0 # EASY + $game_switches[SWITCH_GAME_DIFFICULTY_EASY] = true + $game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false + when 1 # NORMAL + $game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false + $game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false + when 2 # HARD + $game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false + $game_switches[SWITCH_GAME_DIFFICULTY_HARD] = true + end +end + +# Old menu for changing difficulty - unused +def change_game_difficulty(down_only = false) + message = "The game is currently on " + get_difficulty_text() + " difficulty." + pbMessage(message) + + choice_easy = "Easy" + choice_normal = "Normal" + choice_hard = "Hard" + choice_cancel = "Cancel" + + available_difficulties = [] + currentDifficulty = get_current_game_difficulty + if down_only + if currentDifficulty == :HARD + available_difficulties << choice_hard + available_difficulties << choice_normal + available_difficulties << choice_easy + elsif currentDifficulty == :NORMAL + available_difficulties << choice_normal + available_difficulties << choice_easy + elsif currentDifficulty == :EASY + available_difficulties << choice_easy + end + else + available_difficulties << choice_easy + available_difficulties << choice_normal + available_difficulties << choice_hard + end + available_difficulties << choice_cancel + index = pbMessage("Select a new difficulty", available_difficulties, available_difficulties[-1]) + choice = available_difficulties[index] + case choice + when choice_easy + $game_switches[SWITCH_GAME_DIFFICULTY_EASY] = true + $game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false + when choice_normal + $game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false + $game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false + when choice_hard + $game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false + $game_switches[SWITCH_GAME_DIFFICULTY_HARD] = true + when choice_cancel + return + end + + message = "The game is currently on " + get_difficulty_text() + " difficulty." + pbMessage(message) +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Gameplay/game_start.rb b/Data/Scripts/998_InfiniteFusion/Gameplay/game_start.rb new file mode 100644 index 000000000..fcc7eed24 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Gameplay/game_start.rb @@ -0,0 +1,34 @@ + +SWITCH_GYM_RANDOM_EACH_BATTLE=668 +SWITCH_NO_BUMP_SOUND=108 +SWITCH_HAS_PREVIOUS_SAVEFILE = 972 +VARIABLE_BATTLE_STYLE = 199 + +def setup_new_game() + set_new_game_switches + set_new_game_variables + setup_player + setup_randomizer +end + +def set_new_game_switches + $game_switches[SWITCH_GYM_RANDOM_EACH_BATTLE] = true + $game_switches[SWITCH_NO_BUMP_SOUND] = true + $game_switches[SWITCH_HAS_PREVIOUS_SAVEFILE]= SaveData.exists? +end + +def set_new_game_variables + pbSet(VARIABLE_BATTLE_STYLE,0) +end + +def setup_player + $player.has_running_shoes=true + #pbChangePlayer(0) +end + +def setup_randomizer + #init the random items hash even if it's not used + + #pbShuffleItems + #pbShuffleTMs +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/InfiniteFusionSettings.rb b/Data/Scripts/998_InfiniteFusion/InfiniteFusionSettings.rb new file mode 100644 index 000000000..88e752978 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/InfiniteFusionSettings.rb @@ -0,0 +1,672 @@ +# frozen_string_literal: true + +#==============================================================================# +# Pokémon Essentials # +# Version 19.1.dev # +# https://github.com/Maruno17/pokemon-essentials # +#==============================================================================# +module Settings + # The version of your game. It has to adhere to the MAJOR.MINOR.PATCH format. + GAME_VERSION = '6.5.1' + GAME_VERSION_NUMBER = "6.5.1" + LATEST_GAME_RELEASE = "6.5" + + POKERADAR_LIGHT_ANIMATION_RED_ID = 17 + POKERADAR_LIGHT_ANIMATION_GREEN_ID = 18 + POKERADAR_HIDDEN_ABILITY_POKE_CHANCE = 32 + POKERADAR_BATTERY_STEPS = 0 + + LEADER_VICTORY_MUSIC="Battle victory leader" + TRAINER_VICTORY_MUSIC="trainer-victory" + WILD_VICTORY_MUSIC="wild-victory" + #getRandomCustomFusionForIntro + FUSION_ICON_SPRITE_OFFSET = 10 + + #Infinite fusion settings + NB_POKEMON = 501 + CUSTOM_BASE_SPRITES_FOLDER = "Graphics/CustomBattlers/local_sprites/BaseSprites/" + CUSTOM_BATTLERS_FOLDER = "Graphics/CustomBattlers/" + CUSTOM_SPRITES_TO_IMPORT_FOLDER = "Graphics/CustomBattlers/Sprites to import/" + CUSTOM_BATTLERS_FOLDER_INDEXED = "Graphics/CustomBattlers/local_sprites/indexed/" + CUSTOM_BASE_SPRITE_FOLDER = "Graphics/CustomBattlers/local_sprites/BaseSprites/" + BATTLERS_FOLDER = "Graphics/Battlers/Autogens/" + DOWNLOADED_SPRITES_FOLDER = "Graphics/temp/" + DEFAULT_SPRITE_PATH = "Graphics/Battlers/Special/000.png" + CREDITS_FILE_PATH = "Data/sprites/Sprite Credits.csv" + VERSION_FILE_PATH = "Data/VERSION" + CUSTOM_SPRITES_FILE_PATH = "Data/sprites/CUSTOM_SPRITES" + BASE_SPRITES_FILE_PATH = "Data/sprites/BASE_SPRITES" + CUSTOM_DEX_ENTRIES_PATH = "Data/pokedex/dex.json" + AI_DEX_ENTRIES_PATH = "Data/pokedex/generated_entries.json" + POKEDEX_ENTRIES_PATH = "Data/pokedex/all_entries.json" + + UPDATED_SPRITESHEETS_CACHE = "Data/sprites/updated_spritesheets_cache" + + BACK_ITEM_ICON_PATH = "Graphics/Items/back.png" + + PLAYER_GRAPHICS_FOLDER = "Graphics/Characters/player/" + PLAYER_HAT_FOLDER = 'hat' + PLAYER_HAIR_FOLDER = 'hair' + PLAYER_CLOTHES_FOLDER = 'clothes' + PLAYER_BALL_FOLDER = 'balls' + PLAYER_TEMP_OUTFIT_FALLBACK = 'temp' + + + HATS_DATA_PATH = "Data/outfits/hats_data.json" + HAIRSTYLE_DATA_PATH = "Data/outfits/hairstyles_data.json" + CLOTHES_DATA_PATH = "Data/outfits/clothes_data.json" + + PLAYER_SURFBASE_FOLDER = 'surf_base/' + OW_SHINE_ANIMATION_ID=25 + + HTTP_CONFIGS_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/pif-downloadables/refs/heads/master/Settings.rb" + HTTP_CONFIGS_FILE_PATH = "Data/Scripts/DownloadedSettings.rb" + + SPRITES_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/infinitefusion-e18/main/Data/sprites/CUSTOM_SPRITES" + BASE_SPRITES_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/infinitefusion-e18/main/Data/sprites/BASE_SPRITES" + + CREDITS_FILE_URL = "https://infinitefusion.net/Sprite Credits.csv" + CUSTOM_DEX_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/pif-downloadables/refs/heads/master/dex.json" + + STARTUP_MESSAGES = "" + + LEVEL_CAPS=[12,22,26,35,38,45,51,54,62,62,63,64,64,65,67,68] + + CUSTOM_ENTRIES_NAME_PLACEHOLDER = "POKENAME" + + DEFAULT_SPEED_UP_SPEED=2 + FRONTSPRITE_POSITION_OFFSET = 20 + FRONTSPRITE_SCALE = 0.6666666666666666 + BACKRPSPRITE_SCALE = 1 + EGGSPRITE_SCALE = 1 + BACKSPRITE_POSITION_OFFSET = 20 + FRONTSPRITE_POSITION = 200 + SHINY_HUE_OFFSET = 75 + NO_LEVEL_MODE_LEVEL_INCR = 5.8 + NO_LEVEL_MODE_LEVEL_BASE = 6 + + SAVEFILE_NB_BACKUPS=10 + + DISCORD_URL = "https://discord.com/invite/infinitefusion" + WIKI_URL = "https://infinitefusion.fandom.com/" + + AI_ENTRIES_URL = "https://ai-entries.pkmninfinitefusion.workers.dev/" + AI_ENTRIES_RATE_MAX_NB_REQUESTS = 10 #Nb. requests allowed in each time window + AI_ENTRIES_RATE_TIME_WINDOW = 120 # In seconds + AI_ENTRIES_RATE_LOG_FILE = 'Data/pokedex/dex_rate_limit.log' # Path to the log file + + CUSTOMSPRITES_RATE_MAX_NB_REQUESTS = 15 #Nb. requests allowed in each time window + CUSTOMSPRITES_ENTRIES_RATE_TIME_WINDOW = 120 # In seconds + CUSTOMSPRITES_RATE_LOG_FILE = 'Data/sprites/sprites_rate_limit.log' # Path to the log file + MAX_NB_SPRITES_TO_DOWNLOAD_AT_ONCE=5 + + CUSTOM_SPRITES_REPO_URL = "https://bitbucket.org/infinitefusionsprites/customsprites/raw/main/CustomBattlers/" + CUSTOM_SPRITES_NEW_URL = "https://infinitefusion.net/CustomBattlers/" + + BASE_POKEMON_ALT_SPRITES_REPO_URL = "https://bitbucket.org/infinitefusionsprites/customsprites/raw/main/Other/BaseSprites/" + BASE_POKEMON_ALT_SPRITES_NEW_URL = "https://infinitefusion.net/Other/BaseSprites/" + + BASE_POKEMON_SPRITESHEET_URL = "https://infinitefusion.net/spritesheets/spritesheets_base/" + CUSTOM_FUSIONS_SPRITESHEET_URL = "https://infinitefusion.net/spritesheets/spritesheets_custom/" + + BASE_POKEMON_SPRITESHEET_TRUE_SIZE_URL = "" + CUSTOM_FUSIONS_SPRITESHEET_TRUE_SIZE_URL = "" + + RIVAL_STARTER_PLACEHOLDER_SPECIES = :MEW #(MEW) + VAR_1_PLACEHOLDER_SPECIES = :DIALGA + VAR_2_PLACEHOLDER_SPECIES = :PALKIA + VAR_3_PLACEHOLDER_SPECIES = :GIRATINA + + RIVAL_STARTER_PLACEHOLDER_VARIABLE = 250 + + OVERRIDE_BATTLE_LEVEL_SWITCH = 785 + OVERRIDE_BATTLE_LEVEL_VALUE_VAR = 240 + HARD_MODE_LEVEL_MODIFIER = 1.1 + + ZAPMOLCUNO_NB = 999999#176821 + MAPS_WITHOUT_SURF_MUSIC = [762] + + WONDERTRADE_BASE_URL = "http://localhost:8080" + WONDERTRADE_PUBLIC_KEY = "http://localhost:8080" + + MAX_NB_OUTFITS=99 + + OUTFIT_PREVIEW_PICTURE_ID=20 + + DEFAULT_TRAINER_CARD_BG="BLUE" + + # The generation that the battle system follows. Used throughout the battle + # scripts, and also by some other settings which are used in and out of battle + # (you can of course change those settings to suit your game). + # Note that this isn't perfect. Essentials doesn't accurately replicate every + # single generation's mechanics. It's considered to be good enough. Only + # generations 5 and later are reasonably supported. + MECHANICS_GENERATION = 5 + + #============================================================================= + + # The default screen width (at a scale of 1.0). + SCREEN_WIDTH = 512 + # The default screen height (at a scale of 1.0). + SCREEN_HEIGHT = 384 + # The default screen scale factor. Possible values are 0.5, 1.0, 1.5 and 2.0. + SCREEN_SCALE = 1.0 + + FADEOUT_SPEED = 0.2 + + #============================================================================= + + # The maximum level Pokémon can reach. + MAXIMUM_LEVEL = 100 + # The level of newly hatched Pokémon. + EGG_LEVEL = 1 + # Number of badges in the game + NB_BADGES = 16 + # The odds of a newly generated Pokémon being shiny (out of 65536). + SHINY_POKEMON_CHANCE = 16#(MECHANICS_GENERATION >= 6) ? 16 : 8 + + # The odds of a wild Pokémon/bred egg having Pokérus (out of 65536). + POKERUS_CHANCE = 3 + # Whether a bred baby Pokémon can inherit any TM/HM moves from its father. It + # can never inherit TM/HM moves from its mother. + BREEDING_CAN_INHERIT_MACHINE_MOVES = (MECHANICS_GENERATION <= 5) + # Whether a bred baby Pokémon can inherit egg moves from its mother. It can + # always inherit egg moves from its father. + BREEDING_CAN_INHERIT_EGG_MOVES_FROM_MOTHER = (MECHANICS_GENERATION >= 6) + + KANTO_STARTERS = [:BULBASAUR, :CHARMANDER, :SQUIRTLE] + JOHTO_STARTERS = [:CHIKORITA, :CYNDAQUIL, :TOTODILE] + HOENN_STARTERS = [:TREECKO, :TORCHIC, :MUDKIP] + SINNOH_STARTERS = [:TURTWIG, :CHIMCHAR, :PIPLUP] + KALOS_STARTERS = [:CHESPIN, :FENNEKIN, :FROAKIE] + + + #============================================================================= + + # The amount of money the player starts the game with. + INITIAL_MONEY = 3000 + # The maximum amount of money the player can have. + MAX_MONEY = 999_999 + # The maximum number of Game Corner coins the player can have. + MAX_COINS = 99_999 + # The maximum number of Battle Points the player can have. + MAX_BATTLE_POINTS = 9_999 + # The maximum amount of soot the player can have. + MAX_SOOT = 9_999 + # The maximum length, in characters, that the player's name can be. + MAX_PLAYER_NAME_SIZE = 10 + # The maximum number of Pokémon that can be in the party. + MAX_PARTY_SIZE = 6 + + #============================================================================= + + # A set of arrays each containing a trainer type followed by a Global Variable + # number. If the variable isn't set to 0, then all trainers with the + # associated trainer type will be named as whatever is in that variable. + RIVAL_NAMES = [ + [:RIVAL1, 12], + [:RIVAL2, 12], + [:CHAMPION, 12] + ] + + #============================================================================= + + # Whether outdoor maps should be shaded according to the time of day. + TIME_SHADING = true + + #============================================================================= + + # Whether poisoned Pokémon will lose HP while walking around in the field. + POISON_IN_FIELD = true #(MECHANICS_GENERATION <= 4) + # Whether poisoned Pokémon will faint while walking around in the field + # (true), or survive the poisoning with 1 HP (false). + POISON_FAINT_IN_FIELD = (MECHANICS_GENERATION >= 3) + # Whether planted berries grow according to Gen 4 mechanics (true) or Gen 3 + # mechanics (false). + NEW_BERRY_PLANTS = (MECHANICS_GENERATION >= 4) + # Whether fishing automatically hooks the Pokémon (true), or whether there is + # a reaction test first (false). + FISHING_AUTO_HOOK = false + # The ID of the common event that runs when the player starts fishing (runs + # instead of showing the casting animation). + FISHING_BEGIN_COMMON_EVENT = -1 + # The ID of the common event that runs when the player stops fishing (runs + # instead of showing the reeling in animation). + FISHING_END_COMMON_EVENT = -1 + + #============================================================================= + + # The number of steps allowed before a Safari Zone game is over (0=infinite). + SAFARI_STEPS = 600 + # The number of seconds a Bug Catching Contest lasts for (0=infinite). + BUG_CONTEST_TIME = 20 * 60 # 20 minutes + + #============================================================================= + + # Pairs of map IDs, where the location signpost isn't shown when moving from + # one of the maps in a pair to the other (and vice versa). Useful for single + # long routes/towns that are spread over multiple maps. + # e.g. [4,5,16,17,42,43] will be map pairs 4,5 and 16,17 and 42,43. + # Moving between two maps that have the exact same name won't show the + # location signpost anyway, so you don't need to list those maps here. + NO_SIGNPOSTS = [] + + #============================================================================= + + # Whether you need at least a certain number of badges to use some hidden + # moves in the field (true), or whether you need one specific badge to use + # them (false). The amounts/specific badges are defined below. + FIELD_MOVES_COUNT_BADGES = true + # Depending on FIELD_MOVES_COUNT_BADGES, either the number of badges required + # to use each hidden move in the field, or the specific badge number required + # to use each move. Remember that badge 0 is the first badge, badge 1 is the + # second badge, etc. + # e.g. To require the second badge, put false and 1. + # To require at least 2 badges, put true and 2. + BADGE_FOR_CUT = 1 + BADGE_FOR_FLASH = 1 + BADGE_FOR_ROCKSMASH = 0 + BADGE_FOR_SURF = 6 + BADGE_FOR_FLY = 3 + BADGE_FOR_STRENGTH = 5 + BADGE_FOR_DIVE = 9 + BADGE_FOR_WATERFALL = 9 + BADGE_FOR_TELEPORT = 3 + BADGE_FOR_BOUNCE = 8 + BADGE_FOR_ROCKCLIMB = 16 + #============================================================================= + + # If a move taught by a TM/HM/TR replaces another move, this setting is + # whether the machine's move retains the replaced move's PP (true), or whether + # the machine's move has full PP (false). + TAUGHT_MACHINES_KEEP_OLD_PP = (MECHANICS_GENERATION == 5) + # Whether the Black/White Flutes will raise/lower the levels of wild Pokémon + # respectively (true), or will lower/raise the wild encounter rate + # respectively (false). + FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS = (MECHANICS_GENERATION >= 6) + # Whether Repel uses the level of the first Pokémon in the party regardless of + # its HP (true), or it uses the level of the first unfainted Pokémon (false). + REPEL_COUNTS_FAINTED_POKEMON = (MECHANICS_GENERATION >= 6) + # Whether Rage Candy Bar acts as a Full Heal (true) or a Potion (false). + RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS = (MECHANICS_GENERATION >= 7) + + #============================================================================= + + # The name of the person who created the Pokémon storage system. + def self.storage_creator_name + return _INTL("Bill") + end + + # The number of boxes in Pokémon storage. + NUM_STORAGE_BOXES = 40 + + #============================================================================= + + # The names of each pocket of the Bag. Ignore the first entry (""). + def self.bag_pocket_names + return ["", + _INTL("Items"), + _INTL("Medicine"), + _INTL("Poké Balls"), + _INTL("TMs & HMs"), + _INTL("Berries"), + _INTL("Mail"), + _INTL("Battle Items"), + _INTL("Key Items") + ] + end + + # The maximum number of slots per pocket (-1 means infinite number). Ignore + # the first number (0). + BAG_MAX_POCKET_SIZE = [0, -1, -1, -1, -1, -1, -1, -1, -1] + # The maximum number of items each slot in the Bag can hold. + BAG_MAX_PER_SLOT = 999 + # Whether each pocket in turn auto-sorts itself by item ID number. Ignore the + # first entry (the 0). + BAG_POCKET_AUTO_SORT = [0, false, false, false, true, true, false, false, false] + + #============================================================================= + + # Whether the Pokédex list shown is the one for the player's current region + # (true), or whether a menu pops up for the player to manually choose which + # Dex list to view if more than one is available (false). + USE_CURRENT_REGION_DEX = false + # The names of the Pokédex lists, in the order they are defined in the PBS + # file "regionaldexes.txt". The last name is for the National Dex and is added + # onto the end of this array (remember that you don't need to use it). This + # array's order is also the order of $Trainer.pokedex.unlocked_dexes, which + # records which Dexes have been unlocked (the first is unlocked by default). + # If an entry is just a name, then the region map shown in the Area page while + # viewing that Dex list will be the region map of the region the player is + # currently in. The National Dex entry should always behave like this. + # If an entry is of the form [name, number], then the number is a region + # number. That region's map will appear in the Area page while viewing that + # Dex list, no matter which region the player is currently in. + def self.pokedex_names + return [ + # [_INTL("Kanto Pokédex"), 0] + ] + end + + # Whether all forms of a given species will be immediately available to view + # in the Pokédex so long as that species has been seen at all (true), or + # whether each form needs to be seen specifically before that form appears in + # the Pokédex (false). + DEX_SHOWS_ALL_FORMS = false + # An array of numbers, where each number is that of a Dex list (in the same + # order as above, except the National Dex is -1). All Dex lists included here + # will begin their numbering at 0 rather than 1 (e.g. Victini in Unova's Dex). + DEXES_WITH_OFFSETS = [] + + + #============================================================================= + + # A set of arrays, each containing details of a graphic to be shown on the + # region map if appropriate. The values for each array are as follows: + # * Region number. + # * Game Switch; the graphic is shown if this is ON (non-wall maps only). + # * X coordinate of the graphic on the map, in squares. + # * Y coordinate of the graphic on the map, in squares. + # * Name of the graphic, found in the Graphics/Pictures folder. + # * The graphic will always (true) or never (false) be shown on a wall map. + REGION_MAP_EXTRAS = [ + #[0, 51, 16, 15, "mapHiddenBerth", false], + #[0, 52, 20, 14, "mapHiddenFaraday", false] + ] + + TRIPLE_TYPES = [:QMARKS,:ICEFIREELECTRIC,:FIREWATERELECTRIC,:WATERGROUNDFLYING,:GHOSTSTEELWATER, + :FIREWATERGRASS,:GRASSSTEEL,:BUGSTEELPSYCHIC,:ICEROCKSTEEL] + + #============================================================================= + + # A list of maps used by roaming Pokémon. Each map has an array of other maps + # it can lead to. + ROAMING_AREAS = { + 262 => [261,311], + 311 => [262,312], + 312 => [311], + 261 => [262,288,267], + 288 => [261,267,285], + 267 => [261,288,300,254], + 284 => [288,266,285], + 300 => [267,254], + 254 => [300,265], + 266 => [284,265], + 265 => [266,254], + 285 => [284,288]} + + SEVII_ROAMING = { + 528 => [526], #Treasure beach + 526 => [528,559], #Knot Island + 559 => [526,561,564], #Kindle Road + 561 => [559], #Mt. Ember + 564 => [559,562,563,594], #brine road + 562 => [564], #boon island + 563 => [564,600] , #kin island + 594 => [564,566,603], #water labyrinth + 600 => [563,619], #bond bridge + 619 => [600] , #Berry forest + 566 => [594,603], #Resort gorgeous + 603 => [566,594], #Chrono Island + } + # A set of arrays, each containing the details of a roaming Pokémon. The + # information within each array is as follows: + # * Species. + # * Level. + # * Game Switch; the Pokémon roams while this is ON. + # * Encounter type (0=any, 1=grass/walking in cave, 2=surfing, 3=fishing, + # 4=surfing/fishing). See the bottom of PField_RoamingPokemon for lists. + # * Name of BGM to play for that encounter (optional). + # * Roaming areas specifically for this Pokémon (optional). + ROAMING_SPECIES = [ + # { + # :species => :LATIAS, + # :level => 30, + # :icon => "pin_latias", + # :game_switch => 53, + # :encounter_type => :all, + # :bgm => "Battle roaming" + # }, + # { + # :species => :LATIOS, + # :level => 30, + # :icon => "pin_latios", + # :game_switch => 53, + # :encounter_type => :all, + # :bgm => "Battle roaming" + # }, + # { + # :species => :KYOGRE, + # :level => 40, + # :game_switch => 54, + # :encounter_type => :surfing, + # :areas => { + # 2 => [ 21, 31 ], + # 21 => [2, 31, 69], + # 31 => [2, 21, 69], + # 69 => [ 21, 31 ] + # } + # }, + # { + # :species => :ENTEI, + # :level => 40, + # :icon => "pin_entei", + # :game_switch => 55, + # :encounter_type => :land + # } + ] + + PINKAN_ISLAND_MAPS=[51,46,428,531] + + #============================================================================= + + # A set of arrays, each containing the details of a wild encounter that can + # only occur via using the Poké Radar. The information within each array is as + # follows: + # * Map ID on which this encounter can occur. + # * Probability that this encounter will occur (as a percentage). + # * Species. + # * Minimum possible level. + # * Maximum possible level (optional). + POKE_RADAR_ENCOUNTERS = [ + [78, 50, :FLETCHLING,2,5], #Rt. 1 + [86, 50, :FLETCHLING,2,5], #Rt. 2 + [90, 50, :FLETCHLING,2,5], #Rt. 2 + [491, 50, :SHROOMISH,2,5], #Viridian Forest + [490, 50, :BUDEW,4,9], #Rt. 3 + [106, 50, :NINCADA,8,10], #Rt. 4 + [12, 50, :TOGEPI,10,10], #Rt. 5 + [16, 50, :SLAKOTH,12,15], #Rt. 6 + [413, 50, :DRIFLOON,17,20], #Rt. 7 + [409, 50, :SHINX,17,18], #Rt. 8 + [495, 50, :ARON,12,15], #Rt. 9 + [351, 50, :ARON,12,15], #Rt. 9 + [154, 50, :KLINK,14,17], #Rt. 10 + [155, 50, :NINCADA,12,15], #Rt. 11 + [159, 50, :COTTONEE,22,25], #Rt. 12 + [437, 50, :COTTONEE,22,25], #Rt. 13 + [437, 50, :JOLTIK,22,25], #Rt. 13 + [440, 50, :JOLTIK,22,25], #Rt. 14 + [444, 50, :SOLOSIS,22,25], #Rt. 15 + [438, 50, :NATU,22,25], #Rt. 16 + [146, 50, :KLEFKI,22,25], #Rt. 17 + [517, 50, :FERROSEED,22,25], #Rt. 18 + [445, 50, :BAGON,20,20], #Safari zone 1 + [484, 50, :AXEW,20,20], #Safari zone 2 + [485, 50, :DEINO,20,20], #Safari zone 3 + [486, 50, :LARVITAR,20,20], #Safari zone 4 + [487, 50, :JANGMOO,20,20], #Safari zone 5 + [59, 50, :DUNSPARCE,25,30], #Rt. 21 + [171, 50, :BIDOOF,2,5], #Rt. 22 + [143, 50, :RIOLU,25,25], #Rt. 23 + [8, 50, :BUNEARY,12,13], #Rt. 24 + [145, 50, :ABSOL,30,35], #Rt. 26 + [147, 50, :ABSOL,30,35], #Rt. 27 + [311, 50, :BIDOOF,5,5], #Rt. 29 + [284, 50, :LUXIO,40,45], #Rt. 33 + [288, 50, :VIGOROTH,40,45], #Rt. 32 + [342, 50, :GOLETT,40,45], #Ruins of Alph + [261, 50, :BELLOSSOM,45,50], #Rt. 31 + [262, 50, :BIBAREL,45,50], #Rt. 30 + [265, 50, :KIRLIA,25,30], #Rt. 34 + [254, 50, :SMEARGLE,25,30], #Rt. 35 + [267, 50, :SUDOWOODO,25,30], #Rt. 36 + [500, 50, :FOMANTIS,30,30], #National Park + [266, 50, :BRELOOM,30,30], #Ilex Forest + [670, 50, :WEAVILE,50,50], #Ice mountains + [528, 50, :PYUKUMUKU,20,20], #Treasure Beach + [690, 50, :OCTILLERY,32,45], #Deep Ocean + [561, 50, :FLETCHINDER,32,45], #Mt. Ember + [562, 50, :NINJASK,45,50], #Boon Island + [603, 50, :KECLEON,45,50], #Chrono Island + [654, 50, :WHIMSICOTT,32,45], #Brine Road + [559, 50, :SCRAGGY,32,45] #Kindle Road + ] + + #============================================================================= + + # The Game Switch that is set to ON when the player blacks out. + STARTING_OVER_SWITCH = 1 + # The Game Switch that is set to ON when the player has seen Pokérus in the + # Poké Center (and doesn't need to be told about it again). + SEEN_POKERUS_SWITCH = 2 + # The Game Switch which, while ON, makes all wild Pokémon created be shiny. + SHINY_WILD_POKEMON_SWITCH = 31 + # The Game Switch which, while ON, makes all Pokémon created considered to be + # met via a fateful encounter. + FATEFUL_ENCOUNTER_SWITCH = 32 + + #============================================================================= + + # ID of the animation played when the player steps on grass (grass rustling). + GRASS_ANIMATION_ID = 1 + # ID of the animation played when the player lands on the ground after hopping + # over a ledge (shows a dust impact). + DUST_ANIMATION_ID = 2 + # ID of the animation played when a trainer notices the player (an exclamation + # bubble). + EXCLAMATION_ANIMATION_ID = 3 + # ID of the animation played when a patch of grass rustles due to using the + # Poké Radar. + RUSTLE_NORMAL_ANIMATION_ID = 1 + # ID of the animation played when a patch of grass rustles vigorously due to + # using the Poké Radar. (Rarer species) + RUSTLE_VIGOROUS_ANIMATION_ID = 5 + # ID of the animation played when a patch of grass rustles and shines due to + # using the Poké Radar. (Shiny encounter) + RUSTLE_SHINY_ANIMATION_ID = 6 + # ID of the animation played when a berry tree grows a stage while the player + # is on the map (for new plant growth mechanics only). + PLANT_SPARKLE_ANIMATION_ID = 7 + SLEEP_ANIMATION_ID = 26 + + CUT_TREE_ANIMATION_ID = 19 + ROCK_SMASH_ANIMATION_ID = 20 + + #============================================================================= + + # An array of available languages in the game, and their corresponding message + # file in the Data folder. Edit only if you have 2 or more languages to choose + # from. + LANGUAGES = [ + # ["English", "english.dat"], + # ["Deutsch", "deutsch.dat"] + ] + + + #Technical + SPRITE_CACHE_MAX_NB=100 + NEWEST_SPRITEPACK_MONTH = 12 + NEWEST_SPRITEPACK_YEAR = 2020 + #============================================================================= + + # Available speech frames. These are graphic files in "Graphics/Windowskins/". + SPEECH_WINDOWSKINS = [ + "speech hgss 1", + "speech hgss 2", + "speech hgss 3", + "speech hgss 4", + "speech hgss 5", + "speech hgss 6", + "speech hgss 7", + "speech hgss 8", + "speech hgss 9", + "speech hgss 10", + "speech hgss 11", + "speech hgss 12", + "speech hgss 13", + "speech hgss 14", + "speech hgss 15", + "speech hgss 16", + "speech hgss 17", + "speech hgss 18", + "speech hgss 19", + "speech hgss 20", + "speech pl 18" + ] + + # Available menu frames. These are graphic files in "Graphics/Windowskins/". + MENU_WINDOWSKINS = [ + "default_transparent", + "default_opaque", + "choice 2", + "choice 3", + "choice 4", + "choice 5", + "choice 6", + "choice 7", + "choice 8", + "choice 9", + "choice 10", + "choice 11", + "choice 12", + "choice 13", + "choice 14", + "choice 15", + "choice 16", + "choice 17", + "choice 18", + "choice 19", + "choice 20", + "choice 21", + "choice 22", + "choice 23", + "choice 24", + "choice 25", + "choice 26", + "choice 27", + "choice 28" + ] + + + RANDOMIZED_GYM_TYPE_TM= + { + :NORMAL => [:TM32,:TM49,:TM42,:TM98], #DOUBLETEAM ECHOEDVOICE FACADE BATONPASS + :FIGHTING => [:TM83,:TM115,:TM52,:TM112], #WORKUP POWERUPPUNCH FOCUSBLAST FOCUSPUNCH + :FLYING => [:TM62,:TM58,:TM108,:TM100], #ACROBATICS SKYDROP SKYATTACK DEFOG + :POISON => [:TM84,:TM06,:TM36,:TM34], #POISONJAB TOXIC SLUDGEBOMB SLUDGEWAVE + :GROUND => [:TM28,:TM78,:TM26,:TM119], #DIG BULLDOZE EARTHQUAKE STOMPINGTANTRUM + :ROCK => [:TM39,:TM80,:TM71,:TM69], #ROCKTOMB ROCKTHROW STONEDGE ROCKPOLISH + :BUG => [:TM76,:TM89,:TM113,:TM99], #STRUGGLEBUG UTURN INFESTATION QUIVERDANCE + :GHOST => [:TM85,:TM65,:TM30,:TM97], #DREAMEATER SHADOWCLAW SHADOWBALL NASTYPLOT + :STEEL => [:TM74,:TM118,:TM117,:TM75], # GYROBALL STEELWING SMARTSTRIKE SWORDDANCE + :FIRE => [:TM11,:TM43,:TM38,:TM61], #SUNNYDAY FLAMECHARGE FIREBLAST WILLOWISP + :WATER => [:TM55,:TM105,:TM121,:TM18], #WATERPULSE AQUAJET SCALD RAINDANCE + :GRASS => [:TM22,:TM53,:TM86,:TM102], # SOLARBEAM ENERGYBALL GRASSKNOT SPORE + :ELECTRIC => [:TM73,:TM116,:TM93,:TM72], #THUNDERWAVE SHOCKWAVE WILDCHARGE VOLTSWITCH + :PSYCHIC => [:TM77,:TM03,:TM29,:TM04], #PSYCHUP PSYSHOCK PSYCHIC CALMMIND + :ICE => [:TM110,:TM13,:TM14,:TM07], #AURORAVEIL ICEBEAM BLIZZARD HAIL + :DRAGON => [:TM95,:TM02,:TM82,:TM101], #SNARL DRAGONCLAW DRAGONTAIL DRAGONDANCE + :DARK => [:TM95,:TM46,:TM120,:TM97], #SNARL THIEF THROATCHOP NASTYPLOT + :FAIRY => [:TM45,:TM111,:TM96,:TM104] #ATTRACT DAZZLINGGLEAM MOONBLAST RECOVER + } + + EXCLUDE_FROM_RANDOM_SHOPS=[:RARECANDY] + +end + +# DO NOT EDIT THESE! +module Essentials + VERSION = "19.1.dev" + ERROR_TEXT = "" +end diff --git a/Data/Scripts/998_InfiniteFusion/Items/New Balls.rb b/Data/Scripts/998_InfiniteFusion/Items/New Balls.rb new file mode 100644 index 000000000..ba628ad6b --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Items/New Balls.rb @@ -0,0 +1,128 @@ +# ################### +# ## NEW POKEBALLS # +# ################### +# +# #GENDER BALL (24) - switch le gender du pokemon +# #catch rate: pokeball +# BallHandlers::OnCatch.add(:GENDERBALL,proc{|ball,battle,pokemon| +# if pokemon.gender == 0 +# pokemon.makeFemale +# elsif pokemon.gender == 1 +# pokemon.makeMale +# end +# }) +# +# #BOOST BALL 25 - rend le pokemon traded +# #catch rate: 80% pokeball +# BallHandlers::ModifyCatchRate.add(:TRADEBALL,proc{|ball,catchRate,battle,pokemon| +# catchRate=(catchRate*0.8).floor(1) +# next catchRate +# }) +# BallHandlers::OnCatch.add(:TRADEBALL,proc{|ball,battle,pokemon| +# pokemon.obtain_method = 2 +# }) +# +# #ABILITY BALL 26 - change l'ability +# #catch rate: 60% pokeball +# BallHandlers::ModifyCatchRate.add(:ABILITYBALL,proc{|ball,catchRate,battle,pokemon| +# catchRate=(catchRate*0.6).floor(1) +# next catchRate +# }) +# BallHandlers::OnCatch.add(:ABILITYBALL,proc{|ball,battle,pokemon| +# species = getSpecies(dexNum(pokemon)) +# ability = species.hidden_abilities[-1] +# pokemon.ability = ability +# pokemon.ability_index= getAbilityIndexFromID(ability,pokemon) +# }) +# +# #VIRUS BALL 27 - give pokerus +# #catch rate: 40% pokeball +# BallHandlers::ModifyCatchRate.add(:VIRUSBALL,proc{|ball,catchRate,battle,pokemon| +# catchRate=(catchRate*0.4).floor(1) +# next catchRate +# }) +# BallHandlers::OnCatch.add(:VIRUSBALL,proc{|ball,battle,pokemon| +# pokemon.givePokerus +# }) +# +# #SHINY BALL 28 - rend shiny +# #catchrate: 20% pokeball +# BallHandlers::ModifyCatchRate.add(:SHINYBALL,proc{|ball,catchRate,battle,pokemon| +# catchRate=(catchRate*0.2).floor(1) +# next catchRate +# }) +# BallHandlers::OnCatch.add(:SHINYBALL,proc{|ball,battle,pokemon| +# pokemon.glitter=true +# }) +# +# #PERFECTBALL 29 +# #catch rate: 10% pokeball +# BallHandlers::ModifyCatchRate.add(:PERFECTBALL,proc{|ball,catchRate,battle,pokemon| +# catchRate=(catchRate*0.1).floor(1) +# next catchRate +# }) +# BallHandlers::OnCatch.add(:PERFECTBALL,proc{|ball,battle,pokemon| +# stats = [:ATTACK, :SPECIAL_ATTACK, :SPECIAL_DEFENSE, :SPEED, :DEFENSE, :HP] +# first = rand(stats.length) +# second = rand(stats.length) +# pokemon.iv[stats[first]] = 31 +# pokemon.iv[stats[second]] = 31 +# }) +# +# +# #DREAMBALL - endormi +# BallHandlers::ModifyCatchRate.add(:DREAMBALL,proc{|ball,catchRate,battle,battler| +# battler.status = :SLEEP +# next catchRate +# }) +# #TOXICBALL - empoisonné +# BallHandlers::ModifyCatchRate.add(:TOXICBALL,proc{|ball,catchRate,battle,battler| +# battler.status = :POISON +# next catchRate +# }) +# #SCORCHBALL - brulé +# BallHandlers::ModifyCatchRate.add(:SCORCHBALL,proc{|ball,catchRate,battle,battler| +# battler.status = :BURN +# next catchRate +# }) +# #FROSTBALL - frozen +# BallHandlers::ModifyCatchRate.add(:FROSTBALL,proc{|ball,catchRate,battle,battler| +# battler.status = :FROZEN +# next catchRate +# }) +# #SPARKBALL - paralizé +# BallHandlers::ModifyCatchRate.add(:SPARKBALL,proc{|ball,catchRate,battle,battler| +# battler.status = :PARALYSIS +# next catchRate +# }) +# #PUREBALL - marche mieux quand pas de status +# BallHandlers::ModifyCatchRate.add(:PUREBALL,proc{|ball,catchRate,battle,battler| +# catchRate=(catchRate*7/2).floor if battler.status ==0 +# next catchRate +# }) +# #STATUSBALL - marche mieux quand any status +# BallHandlers::ModifyCatchRate.add(:STATUSBALL,proc{|ball,catchRate,battle,battler| +# catchRate=(catchRate*5/2).floor if battler.status !=0 +# next catchRate +# }) +# +# #FUSIONBALL - marche mieux quand fusedr +# BallHandlers::ModifyCatchRate.add(:FUSIONBALL,proc{|ball,catchRate,battle,battler| +# catchRate*=3 if GameData::Species.get(battler.species).id_number > Settings::NB_POKEMON +# next catchRate +# }) +# +# #CANDY BALL - +5 level +# #catchrate: 80% pokeball +# BallHandlers::ModifyCatchRate.add(:CANDYBALL,proc{|ball,catchRate,battle,pokemon| +# catchRate=(catchRate*0.8).floor +# next catchRate +# }) +# BallHandlers::OnCatch.add(:CANDYBALL,proc{|ball,battle,pokemon| +# pokemon.level = pokemon.level+5 +# }) +# #FIRECRACKER +# BallHandlers::ModifyCatchRate.add(:FIRECRACKER,proc{|ball,catchRate,battle,battler| +# battler.hp -= 10 +# next 0 +# }) diff --git a/Data/Scripts/998_InfiniteFusion/Items/New HMs.rb b/Data/Scripts/998_InfiniteFusion/Items/New HMs.rb new file mode 100644 index 000000000..729fdfa14 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Items/New HMs.rb @@ -0,0 +1,141 @@ + +#=============================================================================== +# Rock Smash +#=============================================================================== + + +def pbRockSmashRandomEncounter + if rand(100)<30 + if pbEncounter(:RockSmash) + return + else + pbDefaultRockSmashEncounter(5,15) + end + else + rockSmashItem(false) + end +end + +def pbDefaultRockSmashEncounter(minLevel,maxLevel) + level =rand((maxLevel-minLevel).abs)+minLevel + pbWildBattle(:GEODUDE,level) + return true +end + +#FOR ROCK TUNNEL AND CERULEAN CAVE (+diamond) +def pbRockSmashRandomEncounterSpecial + if rand(100)<35 + pbEncounter(:RockSmash) + else + rockSmashItem(true) + end +end + +def getRockSmashItemList(inclRareItems) + basicItems = [:ROCKGEM, :GROUNDGEM,:STEELGEM, + :HARDSTONE,:HARDSTONE,:HARDSTONE,:ROCKGEM, + :SMOOTHROCK,:STARDUST,:HEARTSCALE,:HEARTSCALE, + :HEARTSCALE,:SOFTSAND,:HEARTSCALE,:RAREBONE] + + rareItems = [:RAREBONE,:STARDUST,:ETHER, + :REVIVE,:NUGGET,:DIAMOND] + + fossilItems = [:ROOTFOSSIL,:CLAWFOSSIL,:DOMEFOSSIL,:HELIXFOSSIL, + :SKULLFOSSIL,:ARMORFOSSIL,:JAWFOSSIL,:SAILFOSSIL] + + # Kernel.pbMessage(inclRareItems.to_s) + + itemsList = inclRareItems ? basicItems + basicItems + rareItems : basicItems + + #beaten league + if $game_switches[12] + itemsList += fossilItems + end + return itemsList +end + +def rockSmashItem(isDark=false) + chance = 50 + if rand(100)< chance + if rand(5) == 0 && !hatUnlocked?(HAT_AERODACTYL) + obtainHat(HAT_AERODACTYL) + else + itemsList = getRockSmashItemList(isDark) + i = rand(itemsList.length) + Kernel.pbItemBall(itemsList[i],1,nil,false) + end + end +end + + +#Used in underwater maps +def pbRockSmashRandomEncounterDive + if rand(100)<25 + pbEncounter(:RockSmash) + else + if rand(100)<20 + itemsList = [:WATERGEM,:STEELGEM, + :HEARTSCALE,:HEARTSCALE,:HARDSTONE,:ROCKGEM, + :SMOOTHROCK,:WATERSTONE,:PEARL,:HEARTSCALE, + :HEARTSCALE,:HEARTSCALE,:SHOALSHELL,:BIGPEARL] + + i = rand(itemsList.length) + Kernel.pbItemBall(itemsList[i],1,nil,false) + end + end +end + + + +############### MORNING SUN / MOONLIGHT +HiddenMoveHandlers::CanUseMove.add(:MORNINGSUN,proc{|move,pkmn| + mapMetadata = GameData::MapMetadata.try_get($game_map.map_id) + if !mapMetadata || !mapMetadata.outdoor_map + Kernel.pbMessage(_INTL("Can't use that here.")) + next false + end + next true +}) + +HiddenMoveHandlers::UseMove.add(:MORNINGSUN,proc{|move,pokemon| + Kernel.pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name)) + pbHiddenMoveAnimation(pokemon) + pbFadeOutIn(99999){ + pbSkipTime(9) + newTime = pbGetTimeNow.strftime("%I:%M %p") + Kernel.pbMessage(_INTL("{1} waited until morning...",$Trainer.name)) + Kernel.pbMessage(_INTL("The time is now {1}",newTime)) + $game_screen.weather(:None,0,0) + $game_map.refresh + } + next true +}) + +HiddenMoveHandlers::CanUseMove.add(:MOONLIGHT,proc{|move,pkmn| + mapMetadata = GameData::MapMetadata.try_get($game_map.map_id) + if !mapMetadata || !mapMetadata.outdoor_map + Kernel.pbMessage(_INTL("Can't use that here.")) + next false + end + next true +}) + +HiddenMoveHandlers::UseMove.add(:MOONLIGHT,proc{|move,pokemon| + Kernel.pbMessage(_INTL("{1} used {2}!",pokemon.name,GameData::Move.get(move).name)) + pbHiddenMoveAnimation(pokemon) + pbFadeOutIn(99999){ + pbSkipTime(21) + newTime = pbGetTimeNow.strftime("%I:%M %p") + Kernel.pbMessage(_INTL("{1} waited until night...",$Trainer.name)) + Kernel.pbMessage(_INTL("The time is now {1}",newTime)) + $game_screen.weather(:None,0,0) + $game_map.refresh + } + next true +}) + +def pbSkipTime(newTime) + currentTime = pbGetTimeNow.hour + hoursToAdd = newTime - currentTime + $game_variables[UnrealTime::EXTRA_SECONDS] += hoursToAdd*3600 +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Items/New Items effects.rb b/Data/Scripts/998_InfiniteFusion/Items/New Items effects.rb new file mode 100644 index 000000000..8c1cd60c5 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Items/New Items effects.rb @@ -0,0 +1,1511 @@ +ItemHandlers::UseInBattle.add(:POKEDOLL, proc { |item, battler, battle| + battle.decision = 3 + battle.pbDisplayPaused(_INTL("Got away safely!")) +}) + +ItemHandlers::UseFromBag.add(:LANTERN, proc { |item| + if useLantern() + next 1 + else + next 0 + end +}) + +ItemHandlers::UseInField.add(:LANTERN, proc { |item| + Kernel.pbMessage(_INTL("#{$Trainer.name} used the lantern.")) + if useLantern() + next 1 + else + next 0 + end +}) + +def useLantern() + darkness = $PokemonTemp.darknessSprite + if !darkness || darkness.disposed? || $PokemonGlobal.flashUsed + Kernel.pbMessage(_INTL("It's already illuminated...")) + return false + end + Kernel.pbMessage(_INTL("The Lantern illuminated the area!")) + darkness.radius += 176 + $PokemonGlobal.flashUsed = true + while darkness.radius < 176 + Graphics.update + Input.update + pbUpdateSceneMapd + darkness.radius += 4 + end + return true +end + +ItemHandlers::UseFromBag.add(:TELEPORTER, proc { |item| + if useTeleporter() + next 1 + else + next 0 + end +}) + +ItemHandlers::UseInField.add(:TELEPORTER, proc { |item| + if useTeleporter() + next 1 + else + next 0 + end +}) + +def useTeleporter() + if HiddenMoveHandlers.triggerCanUseMove(:TELEPORT, 0, true) + Kernel.pbMessage(_INTL("Teleport to where?", $Trainer.name)) + ret = pbBetterRegionMap(-1, true, true) + return false unless ret + ############################################### + if ret + $PokemonTemp.flydata = ret + end + # scene = PokemonRegionMapScene.new(-1, false) + # screen = PokemonRegionMap.new(scene) + # ret = screen.pbStartFlyScreen + # if ret + # $PokemonTemp.flydata = ret + # end + end + + if !$PokemonTemp.flydata + return false + else + Kernel.pbMessage(_INTL("{1} used the teleporter!", $Trainer.name)) + pbFadeOutIn(99999) { + Kernel.pbCancelVehicles + $game_temp.player_new_map_id = $PokemonTemp.flydata[0] + $game_temp.player_new_x = $PokemonTemp.flydata[1] + $game_temp.player_new_y = $PokemonTemp.flydata[2] + $PokemonTemp.flydata = nil + $game_temp.player_new_direction = 2 + $scene.transfer_player + $game_map.autoplay + $game_map.refresh + } + pbEraseEscapePoint + return true + end +end + +ItemHandlers::UseInBattle.add(:POKEDOLL, proc { |item, battler, battle| + battle.decision = 3 + battle.pbDisplayPaused(_INTL("Got away safely!")) +}) + +ItemHandlers::UseFromBag.add(:LANTERN, proc { |item| + darkness = $PokemonTemp.darknessSprite + if !darkness || darkness.disposed? + Kernel.pbMessage(_INTL("The cave is already illuminated.")) + next false + end + Kernel.pbMessage(_INTL("The Lantern illuminated the area!")) + $PokemonGlobal.flashUsed = true + darkness.radius += 176 + while darkness.radius < 176 + Graphics.update + Input.update + pbUpdateSceneMap + darkness.radius += 4 + end + next true +}) + +ItemHandlers::UseOnPokemon.add(:TRANSGENDERSTONE, proc { |item, pokemon, scene| + if pokemon.gender == 0 + pokemon.makeFemale + scene.pbRefresh + scene.pbDisplay(_INTL("The Pokémon became female!")) + next true + elsif pokemon.gender == 1 + pokemon.makeMale + scene.pbRefresh + scene.pbDisplay(_INTL("The Pokémon became male!")) + + next true + else + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end +}) + +# NOT FULLY IMPLEMENTED +ItemHandlers::UseOnPokemon.add(:SECRETCAPSULE, proc { |item, poke, scene| + abilityList = poke.getAbilityList + numAbilities = abilityList[0].length + + if numAbilities <= 2 + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + elsif abilityList[0].length <= 3 + if changeHiddenAbility1(abilityList, scene, poke) + next true + end + next false + else + if changeHiddenAbility2(abilityList, scene, poke) + next true + end + next false + end +}) + +def changeHiddenAbility1(abilityList, scene, poke) + abID1 = abilityList[0][2] + msg = _INTL("Change {1}'s ability to {2}?", poke.name, PBAbilities.getName(abID1)) + if Kernel.pbConfirmMessage(_INTL(msg)) + poke.setAbility(2) + abilName1 = PBAbilities.getName(abID1) + scene.pbDisplay(_INTL("{1}'s ability was changed to {2}!", poke.name, PBAbilities.getName(abID1))) + return true + else + return false + end +end + +def changeHiddenAbility2(abilityList, scene, poke) + return false if !Kernel.pbConfirmMessage(_INTL("Change {1}'s ability?", poke.name)) + + abID1 = abilityList[0][2] + abID2 = abilityList[0][3] + + abilName2 = PBAbilities.getName(abID1) + abilName3 = PBAbilities.getName(abID2) + + if (Kernel.pbMessage("Choose an ability.", [_INTL("{1}", abilName2), _INTL("{1}", abilName3)], 2)) == 0 + poke.setAbility(2) + scene.pbDisplay(_INTL("{1}'s ability was changed to {2}!", poke.name, abilName2)) + else + return false + end + poke.setAbility(3) + scene.pbDisplay(_INTL("{1}'s ability was changed to {2}!", poke.name, abilName3)) + return true +end + +ItemHandlers::UseOnPokemon.add(:ROCKETMEAL, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 100, scene) +}) + +ItemHandlers::BattleUseOnPokemon.add(:ROCKETMEAL, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 100, scene) +}) + +ItemHandlers::UseOnPokemon.add(:FANCYMEAL, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 100, scene) +}) + +ItemHandlers::BattleUseOnPokemon.add(:FANCYMEAL, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 100, scene) +}) + +ItemHandlers::UseOnPokemon.add(:COFFEE, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 50, scene) +}) + +ItemHandlers::BattleUseOnPokemon.add(:COFFEE, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 50, scene) +}) + +ItemHandlers::UseOnPokemon.add(:RAGECANDYBAR, proc { |item, pokemon, scene| + if pokemon.level <= 1 + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + else + pbChangeLevel(pokemon, pokemon.level - 1, scene) + scene.pbHardRefresh + next true + end +}) + +ItemHandlers::UseOnPokemon.add(:INCUBATOR, proc { |item, pokemon, scene| + if pokemon.egg? + if pokemon.eggsteps <= 1 + scene.pbDisplay(_INTL("The egg is already ready to hatch!")) + next false + else + scene.pbDisplay(_INTL("Incubating...")) + scene.pbDisplay(_INTL("...")) + scene.pbDisplay(_INTL("...")) + scene.pbDisplay(_INTL("Your egg is ready to hatch!")) + pokemon.eggsteps = 1 + next true + end + else + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end +}) + +ItemHandlers::UseOnPokemon.add(:MISTSTONE, proc { |item, pokemon, scene| + next false if pokemon.egg? + if pbForceEvo(pokemon) + next true + else + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end +}) + +ItemHandlers::UseFromBag.add(:DEBUGGER, proc { |item| + Kernel.pbMessage(_INTL("[{1}]The debugger should ONLY be used if you are stuck somewhere because of a glitch.", Settings::GAME_VERSION_NUMBER)) + if Kernel.pbConfirmMessageSerious(_INTL("Innapropriate use of this item can lead to unwanted effects and make the game unplayable. Do you want to continue?")) + $game_player.cancelMoveRoute() + Kernel.pbStartOver(false) + pbCommonEvent(COMMON_EVENT_FIX_GAME) + Kernel.pbMessage(_INTL("Please report the glitch on the game's Discord, in the #bug-reports channel.")) + openUrlInBrowser(Settings::DISCORD_URL) + next 1 + else + next 0 + end +}) + +def useSleepingBag() + currentSecondsValue = pbGet(UnrealTime::EXTRA_SECONDS) + choices = ["1 hour", "6 hours", "12 hours", "24 hours", "Cancel"] + choice = Kernel.pbMessage("Sleep for how long?", choices, choices.length) + echoln choice + return 0 if choice == choices.length - 1 + oldDay = getDayOfTheWeek() + timeAdded = 0 + case choice + when 0 + timeAdded = 3600 + when 1 + timeAdded = 21600 + when 2 + timeAdded = 43200 + when 3 + timeAdded = 86400 + end + pbSet(UnrealTime::EXTRA_SECONDS, currentSecondsValue + timeAdded) + pbSEPlay("Sleep", 100) + pbFadeOutIn { + Kernel.pbMessage(_INTL("{1} slept for a while...", $Trainer.name)) + } + time = pbGetTimeNow.strftime("%I:%M %p") + newDay = getDayOfTheWeek() + if newDay != oldDay + Kernel.pbMessage(_INTL("The current time is now {1} on {2}.", time, newDay.downcase.capitalize)) + else + Kernel.pbMessage(_INTL("The current time is now {1}.", time)) + end + return 1 +end + +ItemHandlers::UseFromBag.add(:SLEEPINGBAG, proc { |item| + mapMetadata = GameData::MapMetadata.try_get($game_map.map_id) + if !mapMetadata || !mapMetadata.outdoor_map + Kernel.pbMessage(_INTL("Can't use that here...")) + next 0 + end + next useSleepingBag() +}) + +ItemHandlers::UseInField.add(:SLEEPINGBAG, proc { |item| + mapMetadata = GameData::MapMetadata.try_get($game_map.map_id) + if !mapMetadata || !mapMetadata.outdoor_map + Kernel.pbMessage(_INTL("Can't use that here...")) + next 0 + end + next useSleepingBag() +}) + +ItemHandlers::UseFromBag.add(:ROCKETUNIFORM, proc { |item| + next useRocketUniform() +}) + +ItemHandlers::UseInField.add(:ROCKETUNIFORM, proc { |item| + next useRocketUniform() +}) + +ItemHandlers::UseFromBag.add(:FAVORITEOUTFIT, proc { |item| + next useFavoriteOutfit() +}) + +ItemHandlers::UseInField.add(:FAVORITEOUTFIT, proc { |item| + next useFavoriteOutfit() +}) + +ItemHandlers::UseInField.add(:EMERGENCYWHISTLE, proc { |item| + if isOnPinkanIsland() + pbCommonEvent(COMMON_EVENT_PINKAN_WHISTLE) + $scene.reset_map(true) + updatePinkanBerryDisplay() + next 1 + end + next 0 +}) + +ItemHandlers::UseFromBag.add(:EMERGENCYWHISTLE, proc { |item| + if isOnPinkanIsland() + pbCommonEvent(COMMON_EVENT_PINKAN_WHISTLE) + $scene.reset_map(true) + updatePinkanBerryDisplay() + next 1 + end + next 0 +}) + +ItemHandlers::UseFromBag.add(:ODDKEYSTONE, proc { |item| + TOTAL_SPIRITS_NEEDED = 108 + nbSpirits = pbGet(VAR_ODDKEYSTONE_NB) + if nbSpirits == 107 + Kernel.pbMessage(_INTL("The Odd Keystone appears to be moving on its own.")) + Kernel.pbMessage(_INTL("Voices can be heard whispering from it...")) + Kernel.pbMessage(_INTL("Just... one... more...")) + elsif nbSpirits < TOTAL_SPIRITS_NEEDED + nbNeeded = TOTAL_SPIRITS_NEEDED - nbSpirits + Kernel.pbMessage(_INTL("Voices can be heard whispering from the Odd Keystone...")) + Kernel.pbMessage(_INTL("Bring... us... {1}... spirits", nbNeeded.to_s)) + else + Kernel.pbMessage(_INTL("The Odd Keystone appears to be moving on its own.")) + Kernel.pbMessage(_INTL("It seems as if some poweful energy is trying to escape from it.")) + if (Kernel.pbMessage("Let it out?", ["No", "Yes"], 0)) == 1 + pbWildBattle(:SPIRITOMB, 27) + pbSet(VAR_ODDKEYSTONE_NB, 0) + end + next 1 + end +}) + +def useFavoriteOutfit() + cmd_switch = isWearingFavoriteOutfit() ? "Take off favorite outfit" : "Switch to favorite outfit" + cmd_mark_favorite = "Mark current outfit as favorite" + cmd_cancel = "Cancel" + + options = [cmd_switch, cmd_mark_favorite, cmd_cancel] + choice = optionsMenu(options) + if options[choice] == cmd_switch + switchToFavoriteOutfit() + elsif options[choice] == cmd_mark_favorite + pbSEPlay("shiny", 80, 100) + $Trainer.favorite_clothes= $Trainer.clothes + $Trainer.favorite_hat = $Trainer.hat + $Trainer.favorite_hat2=$Trainer.hat2 + pbMessage(_INTL("Your favorite outfit was updated!")) + end +end + +def switchToFavoriteOutfit() + if !$Trainer.favorite_clothes && !$Trainer.favorite_hat && !$Trainer.favorite_hat2 + pbMessage(_INTL("You can mark clothes and hats as your favorites in the outfits menu and use this to quickly switch to them!")) + return 0 + end + + if isWearingFavoriteOutfit() + if (Kernel.pbConfirmMessage("Remove your favorite outfit?")) + last_worn_clothes_is_favorite = $Trainer.last_worn_outfit == $Trainer.favorite_clothes + last_worn_hat_is_favorite = $Trainer.last_worn_hat == $Trainer.favorite_hat + last_worn_hat2_is_favorite = $Trainer.last_worn_hat2 == $Trainer.favorite_hat2 + if (last_worn_clothes_is_favorite && last_worn_hat_is_favorite && last_worn_hat2_is_favorite) + $Trainer.last_worn_outfit = getDefaultClothes() + end + playOutfitChangeAnimation() + putOnClothes($Trainer.last_worn_outfit, true) #if $Trainer.favorite_clothes + putOnHat($Trainer.last_worn_hat, true,false) #if $Trainer.favorite_hat + putOnHat($Trainer.last_worn_hat2, true,true) #if $Trainer.favorite_hat2 + + else + return 0 + end + + else + if (Kernel.pbConfirmMessage("Put on your favorite outfit?")) + echoln "favorite clothes: #{$Trainer.favorite_clothes}, favorite hat: #{$Trainer.favorite_hat}, favorite hat2: #{$Trainer.favorite_hat2}" + + playOutfitChangeAnimation() + putOnClothes($Trainer.favorite_clothes, true) if $Trainer.favorite_clothes + putOnHat($Trainer.favorite_hat, true, false) if $Trainer.favorite_hat + putOnHat($Trainer.favorite_hat2, true, true) if $Trainer.favorite_hat2 + else + return 0 + end + end +end + +def useRocketUniform() + return 0 if !$game_switches[SWITCH_JOINED_TEAM_ROCKET] + if isWearingTeamRocketOutfit() + if (Kernel.pbConfirmMessage("Remove the Team Rocket uniform?")) + if ($Trainer.last_worn_outfit == CLOTHES_TEAM_ROCKET_MALE || $Trainer.last_worn_outfit == CLOTHES_TEAM_ROCKET_FEMALE) && $Trainer.last_worn_hat == HAT_TEAM_ROCKET + $Trainer.last_worn_outfit = getDefaultClothes() + end + playOutfitChangeAnimation() + putOnClothes($Trainer.last_worn_outfit, true) + putOnHat($Trainer.last_worn_hat, true) + else + return 0 + end + else + if (Kernel.pbConfirmMessage("Put on the Team Rocket uniform?")) + playOutfitChangeAnimation() + gender = pbGet(VAR_TRAINER_GENDER) + if gender == GENDER_MALE + putOnClothes(CLOTHES_TEAM_ROCKET_MALE, true) + else + putOnClothes(CLOTHES_TEAM_ROCKET_FEMALE, true) + end + putOnHat(HAT_TEAM_ROCKET, true) + #$scene.reset_map(true) + end + end + return 1 +end + +def useDreamMirror + visitedMap = $PokemonGlobal.visitedMaps[pbGet(226)] + map_name = visitedMap ? Kernel.getMapName(pbGet(226)).to_s : "an unknown location" + + Kernel.pbMessage(_INTL("You peeked into the Dream Mirror...")) + + Kernel.pbMessage(_INTL("You can see a faint glimpse of {1} in the reflection.", map_name)) +end + +def useStrangePlant + if darknessEffectOnCurrentMap() + Kernel.pbMessage(_INTL("The strange plant appears to be glowing.")) + $scene.spriteset.addUserSprite(LightEffect_GlowPlant.new($game_player)) + else + Kernel.pbMessage(_INTL("It had no effect")) + end + +end + +# DREAMMIRROR +ItemHandlers::UseFromBag.add(:DREAMMIRROR, proc { |item| + useDreamMirror + next 1 +}) + +ItemHandlers::UseInField.add(:DREAMMIRROR, proc { |item| + useDreamMirror + next 1 +}) + +# STRANGE PLANT +ItemHandlers::UseFromBag.add(:STRANGEPLANT, proc { |item| + useStrangePlant() + next 1 +}) + +ItemHandlers::UseInField.add(:STRANGEPLANT, proc { |item| + useStrangePlant() + next 1 +}) + +ItemHandlers::UseFromBag.add(:MAGICBOOTS, proc { |item| + if $DEBUG + if Kernel.pbConfirmMessageSerious(_INTL("Take off the Magic Boots?")) + $DEBUG = false + end + else + if Kernel.pbConfirmMessageSerious(_INTL("Put on the Magic Boots?")) + Kernel.pbMessage(_INTL("Debug mode is now active.")) + $game_switches[ENABLED_DEBUG_MODE_AT_LEAST_ONCE] = true # got debug mode (for compatibility) + $DEBUG = true + end + end + next 1 +}) + +def pbForceEvo(pokemon) + newspecies = getEvolvedSpecies(pokemon) + return false if newspecies == -1 + if newspecies > 0 + evo = PokemonEvolutionScene.new + evo.pbStartScreen(pokemon, newspecies) + evo.pbEvolution + evo.pbEndScreen + end + return true +end + +def getEvolvedSpecies(pokemon) + return pbCheckEvolutionEx(pokemon) { |pokemon, evonib, level, poke| + next pbMiniCheckEvolution(pokemon, evonib, level, poke, true) + } +end + +#(copie de fixEvolutionOverflow dans FusionScene) +def getCorrectEvolvedSpecies(pokemon) + if pokemon.species >= NB_POKEMON + body = getBasePokemonID(pokemon.species) + head = getBasePokemonID(pokemon.species, false) + ret1 = -1; ret2 = -1 + for form in pbGetEvolvedFormData(body) + retB = yield pokemon, form[0], form[1], form[2] + break if retB > 0 + end + for form in pbGetEvolvedFormData(head) + retH = yield pokemon, form[0], form[1], form[2] + break if retH > 0 + end + return ret if ret == retB && ret == retH + return fixEvolutionOverflow(retB, retH, pokemon.species) + else + for form in pbGetEvolvedFormData(pokemon.species) + newspecies = form[2] + end + return newspecies; + end + +end + +######################### +## DNA SPLICERS ####### +######################### + +ItemHandlers::UseOnPokemon.add(:INFINITESPLICERS, proc { |item, pokemon, scene| + next true if pbDNASplicing(pokemon, scene, item) + next false +}) + +ItemHandlers::UseOnPokemon.add(:DNASPLICERS, proc { |item, pokemon, scene| + next true if pbDNASplicing(pokemon, scene, item) + next false +}) + +ItemHandlers::UseInField.add(:DNASPLICERS, proc { |item| + fusion_success = useSplicerFromField(item) + next 3 if fusion_success + next false +}) + +ItemHandlers::UseInField.add(:SUPERSPLICERS, proc { |item| + fusion_success = useSplicerFromField(item) + next 3 if fusion_success + next false +}) + +ItemHandlers::UseInField.add(:INFINITESPLICERS, proc { |item| + fusion_success = useSplicerFromField(item) + next true if fusion_success + next false +}) + +ItemHandlers::UseInField.add(:INFINITESPLICERS2, proc { |item| + fusion_success = useSplicerFromField(item) + next true if fusion_success + next false +}) + +def isSuperSplicersMechanics(item) + return [:SUPERSPLICERS, :INFINITESPLICERS2].include?(item) +end + +def useSplicerFromField(item) + scene = PokemonParty_Scene.new + scene.pbStartScene($Trainer.party, "Select a Pokémon") + screen = PokemonPartyScreen.new(scene, $Trainer.party) + chosen = screen.pbChoosePokemon("Select a Pokémon") + pokemon = $Trainer.party[chosen] + fusion_success = pbDNASplicing(pokemon, scene, item) + screen.pbEndScene + scene.dispose + return fusion_success +end + +ItemHandlers::UseOnPokemon.add(:DNAREVERSER, proc { |item, pokemon, scene| + if !pokemon.isFusion? + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end + if Kernel.pbConfirmMessageSerious(_INTL("Should {1} be reversed?", pokemon.name)) + reverseFusion(pokemon) + scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) + scene.pbRefresh + next true + end + + next false +}) + +def reverseFusion(pokemon) + if pokemon.owner.name == "RENTAL" + pbMessage(_INTL("You cannot reverse a rental pokémon!")) + return + end + + body = getBasePokemonID(pokemon.species, true) + head = getBasePokemonID(pokemon.species, false) + newspecies = (head) * Settings::NB_POKEMON + body + + body_exp = pokemon.exp_when_fused_body + head_exp = pokemon.exp_when_fused_head + + pokemon.exp_when_fused_body = head_exp + pokemon.exp_when_fused_head = body_exp + + pokemon.head_shiny, pokemon.body_shiny = pokemon.body_shiny, pokemon.head_shiny + # play animation + pbFadeOutInWithMusic(99999) { + fus = PokemonEvolutionScene.new + fus.pbStartScreen(pokemon, newspecies, true) + fus.pbEvolution(false, true) + fus.pbEndScreen + } +end + +ItemHandlers::UseOnPokemon.add(:INFINITEREVERSERS, proc { |item, pokemon, scene| + if !pokemon.isFusion? + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end + if Kernel.pbConfirmMessageSerious(_INTL("Should {1} be reversed?", pokemon.name)) + body = getBasePokemonID(pokemon.species, true) + head = getBasePokemonID(pokemon.species, false) + newspecies = (head) * Settings::NB_POKEMON + body + + body_exp = pokemon.exp_when_fused_body + head_exp = pokemon.exp_when_fused_head + + pokemon.exp_when_fused_body = head_exp + pokemon.exp_when_fused_head = body_exp + + # play animation + pbFadeOutInWithMusic(99999) { + fus = PokemonEvolutionScene.new + fus.pbStartScreen(pokemon, newspecies, true) + fus.pbEvolution(false, true) + fus.pbEndScreen + scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) + scene.pbRefresh + } + next true + end + + next false +}) + +# +# def pbDNASplicing(pokemon, scene, supersplicers = false, superSplicer = false) +# if (pokemon.species <= NB_POKEMON) +# if pokemon.fused != nil +# if $Trainer.party.length >= 6 +# scene.pbDisplay(_INTL("Your party is full! You can't unfuse {1}.", pokemon.name)) +# return false +# else +# $Trainer.party[$Trainer.party.length] = pokemon.fused +# pokemon.fused = nil +# pokemon.form = 0 +# scene.pbHardRefresh +# scene.pbDisplay(_INTL("{1} changed Forme!", pokemon.name)) +# return true +# end +# else +# chosen = scene.pbChoosePokemon(_INTL("Fuse with which Pokémon?")) +# if chosen >= 0 +# poke2 = $Trainer.party[chosen] +# if (poke2.species <= NB_POKEMON) && poke2 != pokemon +# #check if fainted +# if pokemon.hp == 0 || poke2.hp == 0 +# scene.pbDisplay(_INTL("A fainted Pokémon cannot be fused!")) +# return false +# end +# if pbFuse(pokemon, poke2, supersplicers) +# pbRemovePokemonAt(chosen) +# end +# elsif pokemon == poke2 +# scene.pbDisplay(_INTL("{1} can't be fused with itself!", pokemon.name)) +# return false +# else +# scene.pbDisplay(_INTL("{1} can't be fused with {2}.", poke2.name, pokemon.name)) +# return false +# +# end +# +# else +# return false +# end +# end +# else +# return true if pbUnfuse(pokemon, scene, supersplicers) +# +# #unfuse +# end +# end +# +# def pbUnfuse(pokemon, scene, supersplicers, pcPosition = nil) +# #pcPosition nil : unfusing from party +# #pcPosition [x,x] : unfusing from pc +# # +# +# if (pokemon.obtain_method == 2 || pokemon.ot != $Trainer.name) # && !canunfuse +# scene.pbDisplay(_INTL("You can't unfuse a Pokémon obtained in a trade!")) +# return false +# else +# if Kernel.pbConfirmMessageSerious(_INTL("Should {1} be unfused?", pokemon.name)) +# if pokemon.species > (NB_POKEMON * NB_POKEMON) + NB_POKEMON #triple fusion +# scene.pbDisplay(_INTL("{1} cannot be unfused.", pokemon.name)) +# return false +# elsif $Trainer.party.length >= 6 && !pcPosition +# scene.pbDisplay(_INTL("Your party is full! You can't unfuse {1}.", pokemon.name)) +# return false +# else +# scene.pbDisplay(_INTL("Unfusing ... ")) +# scene.pbDisplay(_INTL(" ... ")) +# scene.pbDisplay(_INTL(" ... ")) +# +# bodyPoke = getBasePokemonID(pokemon.species, true) +# headPoke = getBasePokemonID(pokemon.species, false) +# +# +# if pokemon.exp_when_fused_head == nil || pokemon.exp_when_fused_body == nil +# new_level = calculateUnfuseLevelOldMethod(pokemon, supersplicers) +# body_level = new_level +# head_level = new_level +# poke1 = Pokemon.new(bodyPoke, body_level) +# poke2 = Pokemon.new(headPoke, head_level) +# else +# exp_body = pokemon.exp_when_fused_body + pokemon.exp_gained_since_fused +# exp_head = pokemon.exp_when_fused_head + pokemon.exp_gained_since_fused +# +# poke1 = Pokemon.new(bodyPoke, pokemon.level) +# poke2 = Pokemon.new(headPoke, pokemon.level) +# poke1.exp = exp_body +# poke2.exp = exp_head +# end +# +# #poke1 = PokeBattle_Pokemon.new(bodyPoke, lev, $Trainer) +# #poke2 = PokeBattle_Pokemon.new(headPoke, lev, $Trainer) +# +# if pcPosition == nil +# box = pcPosition[0] +# index = pcPosition[1] +# $PokemonStorage.pbStoreToBox(poke2, box, index) +# else +# Kernel.pbAddPokemonSilent(poke2, poke2.level) +# end +# #On ajoute l'autre dans le pokedex aussi +# $Trainer.seen[poke1.species] = true +# $Trainer.owned[poke1.species] = true +# $Trainer.seen[poke2.species] = true +# $Trainer.owned[poke2.species] = true +# +# pokemon.species = poke1.species +# pokemon.level = poke1.level +# pokemon.name = poke1.name +# pokemon.moves = poke1.moves +# pokemon.obtain_method = 0 +# poke1.obtain_method = 0 +# +# #scene.pbDisplay(_INTL(p1.to_s + " " + p2.to_s)) +# scene.pbHardRefresh +# scene.pbDisplay(_INTL("Your Pokémon were successfully unfused! ")) +# return true +# end +# end +# end +# end + +def calculateUnfuseLevelOldMethod(pokemon, supersplicers) + if pokemon.level > 1 + if supersplicers + lev = pokemon.level * 0.9 + else + lev = pokemon.obtain_method == 2 ? pokemon.level * 0.65 : pokemon.level * 0.75 + end + else + lev = 1 + end + return lev.floor +end + +def drawFusionPreviewText(viewport, text, x, y) + label_base_color = Color.new(248, 248, 248) + label_shadow_color = Color.new(104, 104, 104) + overlay = BitmapSprite.new(Graphics.width, Graphics.height, viewport).bitmap + textpos = [[text, x, y, 0, label_base_color, label_shadow_color]] + pbDrawTextPositions(overlay, textpos) +end + +def drawPokemonType(pokemon_id, x_pos = 192, y_pos = 264) + width = 66 + + viewport = Viewport.new(0, 0, Graphics.width, Graphics.height) + viewport.z = 1000001 + + overlay = BitmapSprite.new(Graphics.width, Graphics.height, viewport).bitmap + + pokemon = GameData::Species.get(pokemon_id) + typebitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/types")) + type1_number = GameData::Type.get(pokemon.type1).id_number + type2_number = GameData::Type.get(pokemon.type2).id_number + type1rect = Rect.new(0, type1_number * 28, 64, 28) + type2rect = Rect.new(0, type2_number * 28, 64, 28) + if pokemon.type1 == pokemon.type2 + overlay.blt(x_pos + (width / 2), y_pos, typebitmap.bitmap, type1rect) + else + overlay.blt(x_pos, y_pos, typebitmap.bitmap, type1rect) + overlay.blt(x_pos + width, y_pos, typebitmap.bitmap, type2rect) + end + return viewport +end + +ItemHandlers::UseOnPokemon.add(:SUPERSPLICERS, proc { |item, pokemon, scene| + next true if pbDNASplicing(pokemon, scene, item) +}) + +def returnItemsToBag(pokemon, poke2) + + it1 = pokemon.item + it2 = poke2.item + if it1 != nil + $PokemonBag.pbStoreItem(it1, 1) + end + if it2 != nil + $PokemonBag.pbStoreItem(it2, 1) + end + pokemon.item = nil + poke2.item = nil +end + +# A AJOUTER: l'attribut dmgup ne modifie presentement pas +# le damage d'une attaque +# +ItemHandlers::UseOnPokemon.add(:DAMAGEUP, proc { |item, pokemon, scene| + move = scene.pbChooseMove(pokemon, _INTL("Boost Damage of which move?")) + if move >= 0 + # if pokemon.moves[move].damage==0 || pokemon.moves[move].accuracy<=5 || pokemon.moves[move].dmgup >=3 + # scene.pbDisplay(_INTL("It won't have any effect.")) + # next false + # else + # pokemon.moves[move].dmgup+=1 + # pokemon.moves[move].damage +=5 + # pokemon.moves[move].accuracy -=5 + + # movename=PBMoves.getName(pokemon.moves[move].id) + # scene.pbDisplay(_INTL("{1}'s damage increased.",movename)) + # next true + scene.pbDisplay(_INTL("This item has not been implemented into the game yet. It had no effect.")) + next false + # end + end +}) + +##New "stones" +# ItemHandlers::UseOnPokemon.add(:UPGRADE, proc { |item, pokemon, scene| +# if (pokemon.isShadow? rescue false) +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# end +# newspecies = pbCheckEvolution(pokemon, item) +# if newspecies <= 0 +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# else +# pbFadeOutInWithMusic(99999) { +# evo = PokemonEvolutionScene.new +# evo.pbStartScreen(pokemon, newspecies) +# evo.pbEvolution(false) +# evo.pbEndScreen +# scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) +# scene.pbRefresh +# } +# next true +# end +# }) +# +# ItemHandlers::UseOnPokemon.add(:DUBIOUSDISC, proc { |item, pokemon, scene| +# if (pokemon.isShadow? rescue false) +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# end +# newspecies = pbCheckEvolution(pokemon, item) +# if newspecies <= 0 +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# else +# pbFadeOutInWithMusic(99999) { +# evo = PokemonEvolutionScene.new +# evo.pbStartScreen(pokemon, newspecies) +# evo.pbEvolution(false) +# evo.pbEndScreen +# scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) +# scene.pbRefresh +# } +# next true +# end +# }) +# +# ItemHandlers::UseOnPokemon.add(:ICESTONE, proc { |item, pokemon, scene| +# if (pokemon.isShadow? rescue false) +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# end +# newspecies = pbCheckEvolution(pokemon, item) +# if newspecies <= 0 +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# else +# pbFadeOutInWithMusic(99999) { +# evo = PokemonEvolutionScene.new +# evo.pbStartScreen(pokemon, newspecies) +# evo.pbEvolution(false) +# evo.pbEndScreen +# scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) +# scene.pbRefresh +# } +# next true +# end +# }) +# # +# ItemHandlers::UseOnPokemon.add(:MAGNETSTONE, proc { |item, pokemon, scene| +# if (pokemon.isShadow? rescue false) +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# end +# newspecies = pbCheckEvolution(pokemon, item) +# if newspecies <= 0 +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# else +# pbFadeOutInWithMusic(99999) { +# evo = PokemonEvolutionScene.new +# evo.pbStartScreen(pokemon, newspecies) +# evo.pbEvolution(false) +# evo.pbEndScreen +# scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) +# scene.pbRefresh +# } +# next true +# end +# }) + +# easter egg for evolving shellder into slowbro's tail +ItemHandlers::UseOnPokemon.add(:SLOWPOKETAIL, proc { |item, pokemon, scene| + echoln pokemon.species + next false if pokemon.species != :SHELLDER + pbFadeOutInWithMusic(99999) { + evo = PokemonEvolutionScene.new + evo.pbStartScreen(pokemon, :B90H80) + evo.pbEvolution(false) + evo.pbEndScreen + scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) if scene.pbHasAnnotations? + scene.pbRefresh + } + next true + +}) +# +# ItemHandlers::UseOnPokemon.add(:SHINYSTONE, proc { |item, pokemon, scene| +# if (pokemon.isShadow? rescue false) +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# end +# newspecies = pbCheckEvolution(pokemon, item) +# if newspecies <= 0 +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# else +# pbFadeOutInWithMusic(99999) { +# evo = PokemonEvolutionScene.new +# evo.pbStartScreen(pokemon, newspecies) +# evo.pbEvolution(false) +# evo.pbEndScreen +# scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) +# scene.pbRefresh +# } +# next true +# end +# }) +# +# ItemHandlers::UseOnPokemon.add(:DAWNSTONE, proc { |item, pokemon, scene| +# if (pokemon.isShadow? rescue false) +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# end +# newspecies = pbCheckEvolution(pokemon, item) +# if newspecies <= 0 +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# else +# pbFadeOutInWithMusic(99999) { +# evo = PokemonEvolutionScene.new +# evo.pbStartScreen(pokemon, newspecies) +# evo.pbEvolution(false) +# evo.pbEndScreen +# scene.pbRefreshAnnotations(proc { |p| pbCheckEvolution(p, item) > 0 }) +# scene.pbRefresh +# } +# next true +# end +# }) +ItemHandlers::UseOnPokemon.add(:POISONMUSHROOM, proc { |item, pkmn, scene| + if pkmn.status != :POISON + pkmn.status = :POISON + scene.pbRefresh + scene.pbDisplay(_INTL("{1} was poisoned from eating the mushroom.", pkmn.name)) + end + next pbHPItem(pkmn, 10, scene) +}) +ItemHandlers::BattleUseOnPokemon.add(:POISONMUSHROOM, proc { |item, pokemon, battler, choices, scene| + if battler.status != :POISON + battler.status = :POISON + scene.pbRefresh + scene.pbDisplay(_INTL("{1} was poisoned from eating the mushroom.", pokemon.name)) + end + pbBattleHPItem(pokemon, battler, 10, scene) +}) + +ItemHandlers::UseOnPokemon.add(:TINYMUSHROOM, proc { |item, pkmn, scene| + next pbHPItem(pkmn, 10, scene) +}) +ItemHandlers::BattleUseOnPokemon.add(:TINYMUSHROOM, proc { |item, pokemon, battler, choices, scene| + next pbBattleHPItem(pokemon, battler, 50, scene) +}) +ItemHandlers::UseOnPokemon.add(:BIGMUSHROOM, proc { |item, pkmn, scene| + next pbHPItem(pkmn, 10, scene) +}) +ItemHandlers::BattleUseOnPokemon.add(:BIGMUSHROOM, proc { |item, pokemon, battler, choices, scene| + next pbBattleHPItem(pokemon, battler, 50, scene) +}) +ItemHandlers::UseOnPokemon.add(:BALMMUSHROOM, proc { |item, pkmn, scene| + next pbHPItem(pkmn, 999, scene) +}) +ItemHandlers::BattleUseOnPokemon.add(:BALMMUSHROOM, proc { |item, pokemon, battler, choices, scene| + next pbBattleHPItem(pokemon, battler, 999, scene) +}) + +# +# #TRACKER (for roaming legendaries) +# ItemHandlers::UseInField.add(:REVEALGLASS, proc { |item| +# if Settings::ROAMING_SPECIES.length == 0 +# Kernel.pbMessage(_INTL("No roaming Pokémon defined.")) +# else +# text = "\\l[8]" +# min = $game_switches[350] ? 0 : 1 +# for i in min...Settings::ROAMING_SPECIES.length +# poke = Settings::ROAMING_SPECIES[i] +# next if poke == PBSPecies::FEEBAS +# if $game_switches[poke[2]] +# status = $PokemonGlobal.roamPokemon[i] +# if status == true +# if $PokemonGlobal.roamPokemonCaught[i] +# text += _INTL("{1} has been caught.", +# PBSpecies.getName(getID(PBSpecies, poke[0]))) +# else +# text += _INTL("{1} has been defeated.", +# PBSpecies.getName(getID(PBSpecies, poke[0]))) +# end +# else +# curmap = $PokemonGlobal.roamPosition[i] +# if curmap +# mapinfos = $RPGVX ? load_data("Data/MapInfos.rvdata") : load_data("Data/MapInfos.rxdata") +# +# if curmap == $game_map.map_id +# text += _INTL("Beep beep! {1} appears to be nearby!", +# PBSpecies.getName(getID(PBSpecies, poke[0]))) +# else +# text += _INTL("{1} is roaming around {3}", +# PBSpecies.getName(getID(PBSpecies, poke[0])), curmap, +# mapinfos[curmap].name, (curmap == $game_map.map_id) ? _INTL("(this route!)") : "") +# end +# else +# text += _INTL("{1} is roaming in an unknown area.", +# PBSpecies.getName(getID(PBSpecies, poke[0])), poke[1]) +# end +# end +# else +# #text+=_INTL("{1} does not appear to be roaming.", +# # PBSpecies.getName(getID(PBSpecies,poke[0])),poke[1],poke[2]) +# end +# text += "\n" if i < Settings::ROAMING_SPECIES.length - 1 +# end +# Kernel.pbMessage(text) +# end +# }) + +####EXP. ALL +# Methodes relative a l'exp sont pas encore la et pas compatibles +# avec cette version de essentials donc +# ca fait fuck all pour l'instant. +ItemHandlers::UseFromBag.add(:EXPALL, proc { |item| + $PokemonBag.pbChangeItem(:EXPALL, :EXPALLOFF) + Kernel.pbMessage(_INTL("The Exp All was turned off.")) + $game_switches[920] = false + next 1 # Continue +}) + +ItemHandlers::UseFromBag.add(:EXPALLOFF, proc { |item| + $PokemonBag.pbChangeItem(:EXPALLOFF, :EXPALL) + Kernel.pbMessage(_INTL("The Exp All was turned on.")) + $game_switches[920] = true + next 1 # Continue +}) + +ItemHandlers::BattleUseOnPokemon.add(:BANANA, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 30, scene) +}) +ItemHandlers::UseOnPokemon.add(:BANANA, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 30, scene) +}) + +ItemHandlers::BattleUseOnPokemon.add(:GOLDENBANANA, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 50, scene) +}) +ItemHandlers::UseOnPokemon.add(:GOLDENBANANA, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 50, scene) +}) + +ItemHandlers::UseOnPokemon.add(:TRANSGENDERSTONE, proc { |item, pokemon, scene| + if pokemon.gender == 0 + pokemon.makeFemale + scene.pbRefresh + scene.pbDisplay(_INTL("The Pokémon became female!")) + next true + elsif pokemon.gender == 1 + pokemon.makeMale + scene.pbRefresh + scene.pbDisplay(_INTL("The Pokémon became male!")) + + next true + else + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end +}) + +# ItemHandlers::UseOnPokemon.add(:ABILITYCAPSULE, proc { |item, poke, scene| +# abilityList = poke.getAbilityList +# abil1 = 0; abil2 = 0 +# for i in abilityList +# abil1 = i[0] if i[1] == 0 +# abil2 = i[1] if i[1] == 1 +# end +# if poke.abilityIndex() >= 2 || abil1 == abil2 +# scene.pbDisplay(_INTL("It won't have any effect.")) +# next false +# end +# if Kernel.pbConfirmMessage(_INTL("Do you want to change {1}'s ability?", +# poke.name)) +# +# if poke.abilityIndex() == 0 +# poke.setAbility(1) +# else +# poke.setAbility(0) +# end +# scene.pbDisplay(_INTL("{1}'s ability was changed!", poke.name)) +# next true +# end +# next false +# +# }) + +# NOT FULLY IMPLEMENTED +ItemHandlers::UseOnPokemon.add(:SECRETCAPSULE, proc { |item, poke, scene| + abilityList = poke.getAbilityList + numAbilities = abilityList[0].length + + if numAbilities <= 2 + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + elsif abilityList[0].length <= 3 + if changeHiddenAbility1(abilityList, scene, poke) + next true + end + next false + else + if changeHiddenAbility2(abilityList, scene, poke) + next true + end + next false + end +}) + +def changeHiddenAbility1(abilityList, scene, poke) + abID1 = abilityList[0][2] + msg = _INTL("Change {1}'s ability to {2}?", poke.name, PBAbilities.getName(abID1)) + if Kernel.pbConfirmMessage(_INTL(msg)) + poke.setAbility(2) + abilName1 = PBAbilities.getName(abID1) + scene.pbDisplay(_INTL("{1}'s ability was changed to {2}!", poke.name, PBAbilities.getName(abID1))) + return true + else + return false + end +end + +def changeHiddenAbility2(abilityList, scene, poke) + return false if !Kernel.pbConfirmMessage(_INTL("Change {1}'s ability?", poke.name)) + + abID1 = abilityList[0][2] + abID2 = abilityList[0][3] + + abilName2 = PBAbilities.getName(abID1) + abilName3 = PBAbilities.getName(abID2) + + if (Kernel.pbMessage("Choose an ability.", [_INTL("{1}", abilName2), _INTL("{1}", abilName3)], 2)) == 0 + poke.setAbility(2) + scene.pbDisplay(_INTL("{1}'s ability was changed to {2}!", poke.name, abilName2)) + else + return false + end + poke.setAbility(3) + scene.pbDisplay(_INTL("{1}'s ability was changed to {2}!", poke.name, abilName3)) + return true +end + +ItemHandlers::UseOnPokemon.add(:ROCKETMEAL, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 100, scene) +}) + +ItemHandlers::BattleUseOnPokemon.add(:ROCKETMEAL, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 100, scene) +}) + +ItemHandlers::UseOnPokemon.add(:FANCYMEAL, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 100, scene) +}) + +ItemHandlers::BattleUseOnPokemon.add(:FANCYMEAL, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 100, scene) +}) + +ItemHandlers::UseOnPokemon.add(:RAGECANDYBAR, proc { |item, pokemon, scene| + if pokemon.level <= 1 + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + else + pbChangeLevel(pokemon, pokemon.level - 1, scene) + scene.pbHardRefresh + next true + end +}) + +ItemHandlers::UseOnPokemon.add(:INCUBATOR, proc { |item, pokemon, scene| + if pokemon.egg? + if pokemon.steps_to_hatch <= 1 + scene.pbDisplay(_INTL("The egg is already ready to hatch!")) + next false + else + scene.pbDisplay(_INTL("Incubating...")) + scene.pbDisplay(_INTL("...")) + scene.pbDisplay(_INTL("...")) + scene.pbDisplay(_INTL("Your egg is ready to hatch!")) + pokemon.steps_to_hatch = 1 + next true + end + else + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end +}) + +ItemHandlers::UseOnPokemon.add(:INCUBATOR_NORMAL, proc { |item, pokemon, scene| + if pokemon.egg? + steps = pokemon.steps_to_hatch + steps = (steps / 1.5).ceil + # steps -= 2000 / (pokemon.nbIncubatorsUsed + 1).ceil + if steps <= 1 + pokemon.steps_to_hatch = 1 + else + pokemon.steps_to_hatch = steps + end + scene.pbDisplay(_INTL("Incubating...")) + scene.pbDisplay(_INTL("...")) + scene.pbDisplay(_INTL("...")) + scene.pbDisplay(_INTL("The egg is closer to hatching!")) + + # if pokemon.steps_to_hatch <= 1 + # scene.pbDisplay(_INTL("Incubating...")) + # scene.pbDisplay(_INTL("...")) + # scene.pbDisplay(_INTL("...")) + # scene.pbDisplay(_INTL("The egg is ready to hatch!")) + # next false + # else + # scene.pbDisplay(_INTL("Incubating...")) + # scene.pbDisplay(_INTL("...")) + # scene.pbDisplay(_INTL("...")) + # if pokemon.nbIncubatorsUsed >= 10 + # scene.pbDisplay(_INTL("The egg is a bit closer to hatching")) + # else + # scene.pbDisplay(_INTL("The egg is closer to hatching")) + # end + # pokemon.incrIncubator() + # next true + # end + else + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end +}) + +ItemHandlers::UseOnPokemon.add(:MISTSTONE, proc { |item, pokemon, scene| + next false if pokemon.egg? + if pbForceEvo(pokemon) + next true + else + scene.pbDisplay(_INTL("It won't have any effect.")) + next false + end +}) + +def pbForceEvo(pokemon) + evolutions = getEvolvedSpecies(pokemon) + return false if evolutions.empty? + # if multiple evolutions, pick a random one + #(format of returned value is [[speciesNum, level]]) + newspecies = evolutions[rand(evolutions.length - 1)][0] + return false if newspecies == nil + evo = PokemonEvolutionScene.new + evo.pbStartScreen(pokemon, newspecies) + evo.pbEvolution + evo.pbEndScreen + return true +end + +# format of returned value is [[speciesNum, evolutionMethod],[speciesNum, evolutionMethod],etc.] +def getEvolvedSpecies(pokemon) + return GameData::Species.get(pokemon.species).get_evolutions(true) +end + +#(copie de fixEvolutionOverflow dans FusionScene) +def getCorrectEvolvedSpecies(pokemon) + if pokemon.species >= NB_POKEMON + body = getBasePokemonID(pokemon.species) + head = getBasePokemonID(pokemon.species, false) + ret1 = -1; ret2 = -1 + for form in pbGetEvolvedFormData(body) + retB = yield pokemon, form[0], form[1], form[2] + break if retB > 0 + end + for form in pbGetEvolvedFormData(head) + retH = yield pokemon, form[0], form[1], form[2] + break if retH > 0 + end + return ret if ret == retB && ret == retH + return fixEvolutionOverflow(retB, retH, pokemon.species) + else + for form in pbGetEvolvedFormData(pokemon.species) + newspecies = form[2] + end + return newspecies; + end + +end + +######################### +## DNA SPLICERS ####### +######################### + +ItemHandlers::UseOnPokemon.add(:INFINITESPLICERS, proc { |item, pokemon, scene| + next true if pbDNASplicing(pokemon, scene, item) + next false +}) + +ItemHandlers::UseOnPokemon.add(:INFINITESPLICERS2, proc { |item, pokemon, scene| + next true if pbDNASplicing(pokemon, scene, item) + next false +}) + +ItemHandlers::UseOnPokemon.add(:DNASPLICERS, proc { |item, pokemon, scene| + next true if pbDNASplicing(pokemon, scene, item) + next false +}) + +ItemHandlers::UseOnPokemon.add(:SUPERSPLICERS, proc { |item, pokemon, scene| + next true if pbDNASplicing(pokemon, scene, item) +}) + + + +# A AJOUTER: l'attribut dmgup ne modifie presentement pas +# le damage d'une attaque +# +ItemHandlers::UseOnPokemon.add(:DAMAGEUP, proc { |item, pokemon, scene| + move = scene.pbChooseMove(pokemon, _INTL("Boost Damage of which move?")) + if move >= 0 + # if pokemon.moves[move].damage==0 || pokemon.moves[move].accuracy<=5 || pokemon.moves[move].dmgup >=3 + # scene.pbDisplay(_INTL("It won't have any effect.")) + # next false + # else + # pokemon.moves[move].dmgup+=1 + # pokemon.moves[move].damage +=5 + # pokemon.moves[move].accuracy -=5 + + # movename=PBMoves.getName(pokemon.moves[move].id) + # scene.pbDisplay(_INTL("{1}'s damage increased.",movename)) + # next true + scene.pbDisplay(_INTL("This item has not been implemented into the game yet. It had no effect.")) + next false + # end + end +}) + + +ItemHandlers::UseFromBag.add(:DEVONSCOPE, proc { |item| + pbQuestlog() + next 1 +}) + +ItemHandlers::UseInField.add(:DEVONSCOPE, proc { |item| + pbQuestlog() +}) + +# TRACKER (for roaming legendaries) +ItemHandlers::UseInField.add(:REVEALGLASS, proc { |item| + track_pokemon() + next true +}) +ItemHandlers::UseFromBag.add(:REVEALGLASS, proc { |item| + track_pokemon() + next true +}) + + +####EXP. ALL +# Methodes relative a l'exp sont pas encore la et pas compatibles +# avec cette version de essentials donc +# ca fait fuck all pour l'instant. +ItemHandlers::UseFromBag.add(:EXPALL, proc { |item| + $PokemonBag.pbChangeItem(:EXPALL, :EXPALLOFF) + Kernel.pbMessage(_INTL("The Exp All was turned off.")) + $game_switches[920] = false + next 1 # Continue +}) + +ItemHandlers::UseFromBag.add(:EXPALLOFF, proc { |item| + $PokemonBag.pbChangeItem(:EXPALLOFF, :EXPALL) + Kernel.pbMessage(_INTL("The Exp All was turned on.")) + $game_switches[920] = true + next 1 # Continue +}) + +ItemHandlers::BattleUseOnPokemon.add(:BANANA, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 30, scene) +}) +ItemHandlers::UseOnPokemon.add(:BANANA, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 30, scene) +}) + +ItemHandlers::BattleUseOnPokemon.add(:GOLDENBANANA, proc { |item, pokemon, battler, scene| + next pbBattleHPItem(pokemon, battler, 50, scene) +}) +ItemHandlers::UseOnPokemon.add(:GOLDENBANANA, proc { |item, pokemon, scene| + next pbHPItem(pokemon, 50, scene) +}) + +ItemHandlers::UseInField.add(:BOXLINK, proc { |item| + blacklisted_maps = [ + 315, 316, 317, 318, 328, 343, # Elite Four + 776, 777, 778, 779, 780, 781, 782, 783, 784, # Mt. Silver + 722, 723, 724, 720, # Dream sequence + 304, 306, 307 # Victory road + ] + if blacklisted_maps.include?($game_map.map_id) + Kernel.pbMessage("There doesn't seem to be any network coverage here...") + else + pbFadeOutIn { + scene = PokemonStorageScene.new + screen = PokemonStorageScreen.new(scene, $PokemonStorage) + screen.pbStartScreen(0) # Boot PC in organize mode + } + end + next 1 +}) \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/LayeredClothes.rb b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/LayeredClothes.rb new file mode 100644 index 000000000..8336fe8cc --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/LayeredClothes.rb @@ -0,0 +1,409 @@ +def find_last_outfit(outfit_type_path, firstOutfit) + for i in firstOutfit..Settings::MAX_NB_OUTFITS + outfit_path = outfit_type_path + "/" + i.to_s #Settings::PLAYER_GRAPHICS_FOLDER + outfit_type_path + "/" + outfit_type_path + "_" + player_sprite + "_" + i.to_s + return i - 1 if !Dir.exist?(outfit_path) + end + return firstOutfit +end + +def list_all_numeric_folders(directory_path) + entries = Dir.entries(directory_path) + # Filter out only the directories whose names are numeric (excluding "." and "..") + numeric_folders = entries.select do |entry| + full_path = File.join(directory_path, entry) + File.directory?(full_path) && entry != '.' && entry != '..' && entry.match?(/^\d+$/) + end + + # Convert the folder names to integers and store in an array + folder_integers = numeric_folders.map(&:to_i) + folder_integers.sort! + return folder_integers +end + +def list_all_numeric_files_with_filter(directory_path, prefix) + entries = Dir.entries(directory_path) + prefixless = [] + for file in entries + next if file == "." || file == ".." + prefixless << file.gsub((prefix + "_"), "") + end + + folder_integers = prefixless.map(&:to_i) + folder_integers.sort! + return folder_integers +end + +#unlocked: +# -1 for all outfits unlocked +# Otherwise, an array of the ids of unlocked outfits +def list_available_outfits(directory, versions = [], unlocked = [], prefix_filter = nil) + if prefix_filter + outfits = list_all_numeric_files_with_filter(directory, prefix_filter) + else + outfits = list_all_numeric_folders(directory) + end + # #echoln outfits + # return outfits #todo: remove this return for unlockable outfits + available_outfits = [] + for outfit in outfits + if !unlocked || unlocked.include?(outfit) + for version in versions + available_outfits << outfit.to_s + version + end + available_outfits << outfit.to_s if versions.empty? + end + end + return available_outfits +end + +def get_current_outfit_position(currentOutfit_id, available_outfits) + current_index = available_outfits.index(currentOutfit_id) + return current_index.nil? ? 0 : current_index +end + +def setHairColor(hue_shift) + $Trainer.hair_color = hue_shift + refreshPlayerOutfit() +end + +def shiftHatColor(incr,secondary_hat=false) + if secondary_hat + $Trainer.hat2_color = 0 if !$Trainer.hat2_color + $Trainer.hat2_color += incr + else + $Trainer.hat_color = 0 if !$Trainer.hat_color + $Trainer.hat_color += incr + end + + refreshPlayerOutfit() +end + +def shiftClothesColor(incr) + $Trainer.clothes_color = 0 if !$Trainer.clothes_color + $Trainer.clothes_color += incr + refreshPlayerOutfit() +end + +def shiftHairColor(incr) + $Trainer.hair_color = 0 if !$Trainer.hair_color + $Trainer.hair_color += incr + echoln "Hair color: #{$Trainer.hair_color}" + refreshPlayerOutfit() +end + +def pbLoadOutfitBitmap(outfitFileName) + begin + outfitBitmap = RPG::Cache.load_bitmap("", outfitFileName) + return outfitBitmap + rescue + return nil + end +end + +def setOutfit(outfit_id) + $Trainer.clothes = outfit_id +end + +def setHat(hat_id) + $Trainer.hat = hat_id +end + +def getEasterEggHeldItem() + map = $game_map.map_id + return "secrets/HOTDOG" if [141, 194].include?(map) #restaurant + return "secrets/SNOWBALL" if [670, 693, 698, 694].include?(map) + return "secrets/WALLET" if [432, 433, 434, 435, 436, 292].include?(map) #dept. store + return "secrets/ALARMCLOCK" if [43, 48, 67, 68, 69, 70, 71, 73].include?(map) #Player room + return "SAFARIBALL" if [445, 484, 485, 486, 107, 487, 488, 717, 82, 75, 74].include?(map) #Safari Zone + return "secrets/WISP" if [401,402,403,467,468,469].include?(map) #Pokemon Tower + return "secrets/SKULL" if [400].include?(map) #Pokemon Tower ground floor + return "secrets/ROCK" if [349,350,800,].include?(map) #Rock Tunnel + return "secrets/MAGIKARP" if [394,471,189,].include?(map) #Fishing huts + return "secrets/AZUREFLUTE" if [694,].include?(map) && $PokemonBag.pbQuantity(:AZUREFLUTE)>=1 #Ice Mountain peak + return "secrets/BIGSODA" if [436,].include?(map) && $PokemonBag.pbQuantity(:SODAPOP)>=1 #Celadon dept. store top + return "secrets/EGG" if [13,406,214,].include?(map) #Day care + return "secrets/STICK" if [266,].include?(map) #Ilex forest + return "secrets/BANANA" if [600,].include?(map) #Bond Bridge + return "secrets/BERRY" if [619,620,].include?(map) #Berry forest + return "secrets/COIN" if [357].include?(map) #Pokemart + return "secrets/LATTE" if [406].include?(map) #Celadon Café + + return nil +end + +def getCurrentPokeball(allowEasterEgg=true) + otherItem = getEasterEggHeldItem() if allowEasterEgg + return otherItem if otherItem + firstPokemon = $Trainer.party[0] + return firstPokemon.poke_ball if firstPokemon + return nil +end + +def generate_front_trainer_sprite_bitmap_from_appearance(trainerAppearance) + echoln trainerAppearance.hat + return generate_front_trainer_sprite_bitmap(false,nil,trainerAppearance.clothes,trainerAppearance.hat,trainerAppearance.hat2, + trainerAppearance.hair,trainerAppearance.skin_color, + trainerAppearance.hair_color,trainerAppearance.hat_color,trainerAppearance.clothes_color, + trainerAppearance.hat2_color) +end + +def generate_front_trainer_sprite_bitmap(allowEasterEgg=true, pokeball = nil, + clothes_id = nil, hat_id = nil, hat2_id=nil, hair_id = nil, + skin_tone_id = nil, hair_color = nil, hat_color = nil, clothes_color = nil, + hat2_color = nil) + + clothes_id = $Trainer.clothes if !clothes_id + hat_id = $Trainer.hat if !hat_id + hat2_id = $Trainer.hat2 if !hat2_id + + hair_id = $Trainer.hair if !hair_id + skin_tone_id = $Trainer.skin_tone if !skin_tone_id + hair_color = $Trainer.hair_color if !hair_color + hat_color = $Trainer.hat_color if !hat_color + hat2_color = $Trainer.hat2_color if !hat2_color + clothes_color = $Trainer.clothes_color if !clothes_color + + hairFilename = getTrainerSpriteHairFilename(hair_id) #_INTL(Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_HAIR_FOLDER + "/hair_trainer_{1}", $Trainer.hair) + outfitFilename = getTrainerSpriteOutfitFilename(clothes_id) #_INTL(Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_CLOTHES_FOLDER + "/clothes_trainer_{1}", $Trainer.clothes) + + hatFilename = getTrainerSpriteHatFilename(hat_id) + hat2Filename = getTrainerSpriteHatFilename(hat2_id) + + pokeball = getCurrentPokeball(allowEasterEgg) if !pokeball + ballFilename = getTrainerSpriteBallFilename(pokeball) if pokeball + + baseFilePath = getBaseTrainerSpriteFilename(skin_tone_id) + + hair_color_shift = hair_color + hat_color_shift = hat_color + hat2_color_shift = hat2_color + clothes_color_shift = clothes_color + + hair_color_shift = 0 if !hair_color_shift + hat_color_shift = 0 if !hat_color_shift + hat2_color_shift = 0 if !hat2_color_shift + + clothes_color_shift = 0 if !clothes_color_shift + + baseBitmap = AnimatedBitmap.new(baseFilePath) if pbResolveBitmap(baseFilePath) + ballBitmap = pbLoadOutfitBitmap(ballFilename) if pbResolveBitmap(ballFilename) + + if !pbResolveBitmap(outfitFilename) + outfitFilename = getTrainerSpriteOutfitFilename(Settings::PLAYER_TEMP_OUTFIT_FALLBACK) + end + if !pbResolveBitmap(outfitFilename) + raise "No temp clothes graphics available" + end + + outfitBitmap = AnimatedBitmap.new(outfitFilename, clothes_color_shift) if pbResolveBitmap(outfitFilename) #pb + hairBitmapWrapper = AnimatedBitmap.new(hairFilename, hair_color_shift) if pbResolveBitmap(hairFilename) + + hatBitmap = AnimatedBitmap.new(hatFilename, hat_color_shift) if pbResolveBitmap(hatFilename) + hat2Bitmap = AnimatedBitmap.new(hat2Filename, hat2_color_shift) if pbResolveBitmap(hat2Filename) + + baseBitmap.bitmap = baseBitmap.bitmap.clone + if outfitBitmap + baseBitmap.bitmap.blt(0, 0, outfitBitmap.bitmap, outfitBitmap.bitmap.rect) + else + outfitFilename = getTrainerSpriteOutfitFilename("temp") + outfitBitmap = AnimatedBitmap.new(outfitFilename, 0) + baseBitmap.bitmap.blt(0, 0, outfitBitmap.bitmap, outfitBitmap.bitmap.rect) + end + baseBitmap.bitmap.blt(0, 0, hairBitmapWrapper.bitmap, hairBitmapWrapper.bitmap.rect) if hairBitmapWrapper + baseBitmap.bitmap.blt(0, 0, hat2Bitmap.bitmap, hat2Bitmap.bitmap.rect) if hat2Bitmap + baseBitmap.bitmap.blt(0, 0, hatBitmap.bitmap, hatBitmap.bitmap.rect) if hatBitmap + baseBitmap.bitmap.blt(44, 42, ballBitmap, ballBitmap.rect) if ballBitmap + + return baseBitmap +end + +def generateNPCClothedBitmapStatic(trainerAppearance,action = "walk") + baseBitmapFilename = getBaseOverworldSpriteFilename(action, trainerAppearance.skin_color) + baseSprite = AnimatedBitmap.new(baseBitmapFilename) + + baseBitmap = baseSprite.bitmap.clone # nekkid sprite + outfitFilename = getOverworldOutfitFilename(trainerAppearance.clothes, action) + + hairFilename = getOverworldHairFilename(trainerAppearance.hair) + + + #Clothes + clothes_color_shift = trainerAppearance.clothes_color || 0 + clothesBitmap = AnimatedBitmap.new(outfitFilename, clothes_color_shift).bitmap if pbResolveBitmap(outfitFilename) + baseBitmap.blt(0, 0, clothesBitmap, clothesBitmap.rect) + #clothesBitmap.dispose + + + #Hair + hair_color_shift = trainerAppearance.hair_color || 0 + hairBitmap = AnimatedBitmap.new(hairFilename, hair_color_shift).bitmap if pbResolveBitmap(hairFilename) + baseBitmap.blt(0, 0, hairBitmap, hairBitmap.rect) + + #Hat + hat_color_shift = trainerAppearance.hat_color || 0 + hat2_color_shift = trainerAppearance.hat2_color || 0 + + hatFilename = getOverworldHatFilename(trainerAppearance.hat) + hat2Filename = getOverworldHatFilename(trainerAppearance.hat2) + + hatBitmapWrapper = AnimatedBitmap.new(hatFilename, hat_color_shift) if pbResolveBitmap(hatFilename) + hat2BitmapWrapper = AnimatedBitmap.new(hat2Filename, hat2_color_shift) if pbResolveBitmap(hat2Filename) + + + if hat2BitmapWrapper + frame_count = 4 # Assuming 4 frames for hair animation; adjust as needed + hat2_frame_bitmap = duplicateHatForFrames(hat2BitmapWrapper.bitmap, frame_count) + + frame_width = baseSprite.bitmap.width / frame_count # Calculate frame width + + frame_count.times do |i| + # Calculate offset for each frame + frame_offset = [i * frame_width, 0] + # Adjust Y offset if frame index is odd + frame_offset[1] -= 2 if i.odd? + positionHat(baseBitmap, hat2_frame_bitmap, frame_offset, i, frame_width) + end + end + + if hatBitmapWrapper + frame_count = 4 # Assuming 4 frames for hair animation; adjust as needed + hat_frame_bitmap = duplicateHatForFrames(hatBitmapWrapper.bitmap, frame_count) + + frame_width = baseSprite.bitmap.width / frame_count # Calculate frame width + + frame_count.times do |i| + # Calculate offset for each frame + frame_offset = [i * frame_width, 0] + # Adjust Y offset if frame index is odd + frame_offset[1] -= 2 if i.odd? + positionHat(baseBitmap, hat_frame_bitmap, frame_offset, i, frame_width) + end + end + + return baseBitmap +end + +#for continue screen +def generateClothedBitmapStatic(trainer, action = "walk") + baseBitmapFilename = getBaseOverworldSpriteFilename(action, trainer.skin_tone) + if !pbResolveBitmap(baseBitmapFilename) + baseBitmapFilename = Settings::PLAYER_GRAPHICS_FOLDER + action + end + baseSprite = AnimatedBitmap.new(baseBitmapFilename) + + # Clone the base sprite bitmap to create the base for the player's sprite + baseBitmap = baseSprite.bitmap.clone # nekkid sprite + outfitFilename = getOverworldOutfitFilename(trainer.clothes, action) + outfitFilename = getOverworldOutfitFilename(Settings::PLAYER_TEMP_OUTFIT_FALLBACK) if !pbResolveBitmap(outfitFilename) + hairFilename = getOverworldHairFilename(trainer.hair) + hatFilename = getOverworldHatFilename(trainer.hat) + hat2Filename = getOverworldHatFilename(trainer.hat2) + + # Use default values if color shifts are not set + hair_color_shift = trainer.hair_color || 0 + hat_color_shift = trainer.hat_color || 0 + hat2_color_shift = trainer.hat2_color || 0 + + clothes_color_shift = trainer.clothes_color || 0 + + # Use fallback outfit if the specified outfit cannot be resolved + if !pbResolveBitmap(outfitFilename) + outfitFilename = Settings::PLAYER_TEMP_OUTFIT_FALLBACK + end + + # Load the outfit and hair bitmaps + outfitBitmap = AnimatedBitmap.new(outfitFilename, clothes_color_shift) + hairBitmapWrapper = AnimatedBitmap.new(hairFilename, hair_color_shift) if pbResolveBitmap(hairFilename) + hatBitmapWrapper = AnimatedBitmap.new(hatFilename, hat_color_shift) if pbResolveBitmap(hatFilename) + hat2BitmapWrapper = AnimatedBitmap.new(hat2Filename, hat2_color_shift) if pbResolveBitmap(hat2Filename) + + # Blit the outfit onto the base sprite + baseBitmap.blt(0, 0, outfitBitmap.bitmap, outfitBitmap.bitmap.rect) if outfitBitmap + + current_offset = [0, 0] # Replace this with getCurrentSpriteOffset() if needed + positionHair(baseBitmap, hairBitmapWrapper.bitmap, current_offset) if hairBitmapWrapper + + frame_count = 4 + frame_width = baseSprite.bitmap.width / frame_count # Calculate frame width + if hat2BitmapWrapper + hat2_frame_bitmap = duplicateHatForFrames(hat2BitmapWrapper.bitmap, frame_count) + frame_count.times do |i| + # Calculate offset for each frame + frame_offset = [i * frame_width, 0] + # Adjust Y offset if frame index is odd + frame_offset[1] -= 2 if i.odd? + positionHat(baseBitmap, hat2_frame_bitmap, frame_offset, i, frame_width) + end + end + if hatBitmapWrapper + hat_frame_bitmap = duplicateHatForFrames(hatBitmapWrapper.bitmap, frame_count) + frame_count.times do |i| + # Calculate offset for each frame + frame_offset = [i * frame_width, 0] + # Adjust Y offset if frame index is odd + frame_offset[1] -= 2 if i.odd? + positionHat(baseBitmap, hat_frame_bitmap, frame_offset, i, frame_width) + end + end + + return baseBitmap +end + +def positionHair(baseBitmap, hairBitmap, offset) + baseBitmap.blt(offset[0], offset[1], hairBitmap, hairBitmap.rect) +end + +def positionHat(baseBitmap, hatBitmap, offset, frame_index, frame_width) + # Define a rect for each frame + frame_rect = Rect.new(frame_index * frame_width, 0, frame_width, hatBitmap.height) + + # Blit only the part of the hat corresponding to the current frame + baseBitmap.blt(offset[0], offset[1], hatBitmap, frame_rect) +end + +def duplicateHatForFrames(hatBitmap, frame_count) + # Create a new bitmap for the duplicated hat frames + frame_width = hatBitmap.width + total_width = frame_width * frame_count + duplicatedBitmap = Bitmap.new(total_width, hatBitmap.height) + + # Copy the single hat frame across each required frame + frame_count.times do |i| + duplicatedBitmap.blt(i * frame_width, 0, hatBitmap, hatBitmap.rect) + end + + return duplicatedBitmap +end + +def add_hat_to_bitmap(bitmap, hat_id, x_pos, y_pos, scale = 1, mirrored = false) + base_scale = 1.5 #coz hat & poke sprites aren't the same size + adjusted_scale = base_scale * scale + hat_filename = getTrainerSpriteHatFilename(hat_id) + hatBitmapWrapper = AnimatedBitmap.new(hat_filename, 0) if pbResolveBitmap(hat_filename) + hatBitmapWrapper.scale_bitmap(adjusted_scale) if hatBitmapWrapper + hatBitmapWrapper.mirror if hatBitmapWrapper && mirrored + bitmap.blt(x_pos * adjusted_scale, y_pos * adjusted_scale, hatBitmapWrapper.bitmap, hatBitmapWrapper.bitmap.rect) if hatBitmapWrapper +end + +class PokemonTemp + attr_accessor :trainer_preview +end + +def display_outfit_preview(x = 320, y = 0, withBorder = true) + hide_outfit_preview() if $PokemonTemp.trainer_preview + $PokemonTemp.trainer_preview = TrainerClothesPreview.new(x, y, withBorder) + $PokemonTemp.trainer_preview.show() +end + +def hide_outfit_preview() + $game_screen.pictures[20].erase + $PokemonTemp.trainer_preview.erase() if $PokemonTemp.trainer_preview + $PokemonTemp.trainer_preview = nil +end + + + + + + + diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitSelector.rb b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitSelector.rb new file mode 100644 index 000000000..ae694a8c1 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitSelector.rb @@ -0,0 +1,174 @@ +class OutfitSelector + attr_reader :clothes_list + attr_reader :hats_list + attr_reader :hairstyles_list + + def initialize() + @clothes_list = parse_clothes_folder() + @hats_list = parse_hats_folder() + @hairstyles_list =parse_hairstyles_folder() + end + + + def parse_clothes_folder + return list_folders(get_clothes_sets_list_path()) + end + + def parse_hats_folder + return list_folders(get_hats_sets_list_path()) + end + + def parse_hairstyle_types_folder + return list_folders(get_hair_sets_list_path()) + end + + def generate_hats_choice(baseOptions=true,additionalIds=[],additionalTags=[],filterOutTags=[]) + list = [] + list += additionalIds + list += search_hats(additionalTags) + if baseOptions + list += get_hats_base_options() + list += search_hats(get_regional_sets_tags()) + end + return list + end + + def generate_clothes_choice(baseOptions=true,additionalIds=[],additionalTags=[],filterOutTags=[]) + list = [] + list += additionalIds + list += search_clothes(additionalTags) + if baseOptions + list += get_clothes_base_options() + list += search_clothes(get_regional_sets_tags()) + end + return list + end + + def generate_hairstyle_choice(baseOptions=true,additionalIds=[],additionalTags=[],filterOutTags=[]) + list = [] + list += additionalIds + list += search_hairstyles(additionalTags) + if baseOptions + list += get_hairstyle_salon_base_options() + list += search_hairstyles(get_regional_sets_tags()) + end + list << HAIR_BALD + return list + end + + def get_regional_sets_tags() + regional_tags = [] + regional_tags << "kanto" if $game_switches[SWITCH_KANTO_HAIR_COLLECTION] + regional_tags << "johto" if $game_switches[SWITCH_JOHTO_HAIR_COLLECTION] + regional_tags << "hoenn" if $game_switches[SWITCH_HOENN_HAIR_COLLECTION] + regional_tags << "sinnoh" if $game_switches[SWITCH_SINNOH_HAIR_COLLECTION] + regional_tags << "unova" if $game_switches[SWITCH_UNOVA_HAIR_COLLECTION] + regional_tags << "kalos" if $game_switches[SWITCH_KALOS_HAIR_COLLECTION] + regional_tags << "alola" if $game_switches[SWITCH_ALOLA_HAIR_COLLECTION] + regional_tags << "galar" if $game_switches[SWITCH_GALAR_HAIR_COLLECTION] + regional_tags << "paldea" if $game_switches[SWITCH_PALDEA_HAIR_COLLECTION] + return regional_tags + end + + def get_hairstyle_salon_base_options() + return search_hairstyles(["default"]) + end + + def get_clothes_base_options() + return search_clothes(["default"]) + end + + def get_hats_base_options() + return search_hats(["default"]) + end + + def parse_hairstyles_folder + hairstyle_types= list_folders(get_hair_sets_list_path()) + max_versions_number = 10 + list= [] + for hairstyle in hairstyle_types + for i in 1..max_versions_number + type = i.to_s + "_" + hairstyle + filePath = getOverworldHairFilename(type) + if pbResolveBitmap(filePath) + list << type + end + end + end + return list + end + + def list_folders(path) + entries= Dir.entries(path) + return entries.select { |entry| File.directory?(File.join(path, entry)) && entry != '.' && entry != '..' } + end + + + def filter_unlocked_outfits(outfits_list,unlocked_outfits) + available_outfits = [] + outfits_list.each do |outfit| + available_outfits << outfit if unlocked_outfits.include?(outfit) + end + return available_outfits + end + + + def selectNextOutfit(currentOutfit, incr, outfits_list, versions = [], allowNone = true, prefix_filter = nil,unlockedOutfits=[],everythingUnlocked=false) + available_outfits = [] + available_outfits = outfits_list if everythingUnlocked + available_outfits << "" if allowNone + available_outfits += filter_unlocked_outfits(outfits_list,unlockedOutfits) if !everythingUnlocked + #available_outfits += list_available_outfits(directory, versions, unlockedOutfits, prefix_filter) #unlockedOutfits = nil for all outfits unlocked + last_outfit = available_outfits[-1] + + current_outfit_index = get_current_outfit_position(currentOutfit, available_outfits) + next_outfit_index = current_outfit_index +incr + + nextOutfit = available_outfits[next_outfit_index] + nextOutfit = last_outfit if next_outfit_index < 0 + + nextOutfit = available_outfits[0] if next_outfit_index >= available_outfits.length() + + return nextOutfit if available_outfits.include?(nextOutfit) + return currentOutfit + end + + def changeToNextClothes(incr,all_unlocked=false) + $Trainer.unlocked_clothes = [] if !$Trainer.unlocked_clothes + + + currentOutfit = $Trainer.clothes + currentOutfit = 0 if !currentOutfit + nextOutfit = selectNextOutfit(currentOutfit, incr, @clothes_list, [], false,nil,$Trainer.unlocked_clothes,all_unlocked) + $Trainer.clothes = nextOutfit + $Trainer.clothes_color = 0 + echoln $Trainer.clothes + + end + + def changeToNextHat(incr,all_unlocked=false) + $Trainer.unlocked_hats = [] if !$Trainer.unlocked_hats + + currentHat = $Trainer.hat + currentHat = 0 if !currentHat + nextOutfit = selectNextOutfit(currentHat, incr, @hats_list, [], true, "hat",$Trainer.unlocked_hats,all_unlocked) + $Trainer.hat = nextOutfit + $Trainer.hat_color = 0 + echoln $Trainer.hat + + end + + def changeToNextHairstyle(incr,all_unlocked=false) + $Trainer.unlocked_hairstyles = [] if !$Trainer.unlocked_hairstyles + + currentHair = $Trainer.hair + currentHair = 0 if !currentHair + nextOutfit = selectNextOutfit(currentHair, incr, @hairstyles_list, ["a", "b", "c", "d"], true,nil,$Trainer.unlocked_hairstyles,all_unlocked) + $Trainer.hair_color = 0 + $Trainer.hair = nextOutfit + echoln $Trainer.hair + + end + + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsGlobal.rb b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsGlobal.rb new file mode 100644 index 000000000..0eef858b6 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsGlobal.rb @@ -0,0 +1,75 @@ +class PokemonGlobalMetadata + attr_accessor :hats_data + attr_accessor :hairstyles_data + attr_accessor :clothes_data +end + +def update_global_hats_list() + file_path = Settings::HATS_DATA_PATH + json_data = File.read(file_path) + hat_data = HTTPLite::JSON.parse(json_data) + + $PokemonGlobal.hats_data = {} + + # Iterate through the JSON data and create Hat objects + hat_data.each do |data| + tags = data['tags'] ? data['tags'].split(',').map(&:strip) : [] + hat = Hat.new( + data['id'], + data['name'], + data['description'], + data['price'], + tags + ) + $PokemonGlobal.hats_data[hat.id] = hat + end +end + +def update_global_hairstyles_list() + file_path = Settings::HAIRSTYLE_DATA_PATH + json_data = File.read(file_path) + hair_data = HTTPLite::JSON.parse(json_data) + + $PokemonGlobal.hairstyles_data = {} + + # Iterate through the JSON data and create Hat objects + hair_data.each do |data| + tags = data['tags'] ? data['tags'].split(',').map(&:strip) : [] + hair = Hairstyle.new( + data['id'], + data['name'], + data['description'], + data['price'], + tags + ) + $PokemonGlobal.hairstyles_data[hair.id] = hair + end +end + +def update_global_clothes_list() + file_path = Settings::CLOTHES_DATA_PATH + json_data = File.read(file_path) + outfits_data = HTTPLite::JSON.parse(json_data) + + $PokemonGlobal.clothes_data = {} + + # Iterate through the JSON data and create Hat objects + outfits_data.each do |data| + tags = data['tags'] ? data['tags'].split(',').map(&:strip) : [] + outfit = Clothes.new( + data['id'], + data['name'], + data['description'], + data['price'], + tags + ) + $PokemonGlobal.clothes_data[outfit.id] = outfit + end +end + +def update_global_outfit_lists() + update_global_hats_list + update_global_hairstyles_list + update_global_clothes_list +end + diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsSearch.rb b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsSearch.rb new file mode 100644 index 000000000..e637c9e7b --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/001_OutfitsMain/OutfitsSearch.rb @@ -0,0 +1,221 @@ +#CLOTHES + +def search_clothes(matching_tags = [], only_unlocked = false) + update_global_outfit_lists() + selector = OutfitSelector.new + + full_data_list = $PokemonGlobal.clothes_data + existing_files_list = selector.parse_clothes_folder() + unlocked_list = $Trainer.unlocked_clothes + return search_outfits_by_tag(full_data_list, matching_tags, existing_files_list, unlocked_list, only_unlocked) +end + +def filter_clothes(filter_tags = [], only_unlocked = false) + update_global_outfit_lists() + selector = OutfitSelector.new + + full_data_list = $PokemonGlobal.hats_data + existing_files_list = selector.parse_hats_folder() + unlocked_list = $Trainer.unlocked_hats + return filter_outfits_by_tag(full_data_list, filter_tags, existing_files_list, unlocked_list, only_unlocked) +end + +def filter_clothes_only_not_owned(clothes_ids_list) + filtered_list = [] + clothes_ids_list.each do|clothe_id| + filtered_list << clothe_id if !$Trainer.unlocked_clothes.include?(clothe_id) + end + return filtered_list +end + +def filter_clothes_only_owned(clothes_ids_list) + filtered_list = [] + clothes_ids_list.each do|clothe_id| + filtered_list << clothe_id if $Trainer.unlocked_clothes.include?(clothe_id) + end + return filtered_list +end + + +#HATS + +def search_hats(matching_tags = [],excluding_tags=[], only_unlocked = false) + update_global_outfit_lists() + selector = OutfitSelector.new + + full_data_list = $PokemonGlobal.hats_data + existing_files_list = selector.parse_hats_folder() + unlocked_list = $Trainer.unlocked_hats + return search_outfits_by_tag(full_data_list, matching_tags, existing_files_list, unlocked_list, only_unlocked,excluding_tags) +end + +def filter_hats(filter_tags = [], only_unlocked = false) + update_global_outfit_lists() + selector = OutfitSelector.new + + full_data_list = $PokemonGlobal.hats_data + existing_files_list = selector.parse_hats_folder() + unlocked_list = $Trainer.unlocked_hats + return filter_outfits_by_tag(full_data_list, filter_tags, existing_files_list, unlocked_list, only_unlocked) +end + +def filter_hats_only_not_owned(hats_ids_list) + filtered_list = [] + hats_ids_list.each do|hat_id| + filtered_list << hat_id if !$Trainer.unlocked_hats.include?(hat_id) + end + return filtered_list +end + +def filter_hats_only_owned(hats_ids_list) + filtered_list = [] + hats_ids_list.each do|hat_id| + filtered_list << hat_id if $Trainer.unlocked_hats.include?(hat_id) + end + return filtered_list +end + + + +#HAIRSTYLES + +def search_hairstyles(matching_tags = [], only_unlocked = false) + update_global_outfit_lists() + selector = OutfitSelector.new + + full_data_list = $PokemonGlobal.hairstyles_data + existing_files_list = selector.parse_hairstyle_types_folder() + return search_outfits_by_tag(full_data_list, matching_tags, existing_files_list, [], false) +end + +def filter_out_hairstyles(filter_tags = [],base_list = [],require_unlocked=false) + update_global_outfit_lists() + selector = OutfitSelector.new + + data_list = $PokemonGlobal.hairstyles_data + existing_files_list = selector.parse_hairstyle_types_folder() + return exclude_outfits_by_tag(data_list, filter_tags, existing_files_list, base_list, false) +end + + + + +# Generic searching methods + +#Get outfits that have ANY of the tags +def search_outfits_by_tag(outfits_map, matching_tags = [], physical_files_list = [], unlocked_list = [], require_unlocked = false, excluding_tags=[]) + filtered_list = [] + outfits_map.each do |outfit_id, outfit| + next if outfit.tags.any? { |tag| excluding_tags.include?(tag) } + if outfit.tags.any? { |tag| matching_tags.include?(tag) } + filtered_list << outfit_id if outfit_is_valid?(outfit_id, physical_files_list, unlocked_list, require_unlocked) + end + end + return filtered_list +end + +#Get outfits that have ALL of the tags +def filter_outfits_by_tag(outfits_map, filter_tags = [], physical_files_list = [], unlocked_list = [], require_unlocked = false) + update_global_outfit_lists() + + filtered_list = [] + outfits_map.each do |outfit_id, outfit| + if filter_tags.all? { |tag| outfit.tags.include?(tag) } + filtered_list << outfit_id if outfit_is_valid?(outfit_id, physical_files_list, unlocked_list, require_unlocked) + end + end + return filtered_list +end + +#Get all outfits from list that DON'T have a tag +def exclude_outfits_by_tag(outfits_map, filter_tags = [], physical_files_list = [], unlocked_list = [], require_unlocked = false) + update_global_outfit_lists() + + filtered_list = [] + outfits_map.each do |outfit_id, outfit| + if filter_tags.any? { |tag| !outfit.tags.include?(tag) } + filtered_list << outfit_id if outfit_is_valid?(outfit_id, physical_files_list, unlocked_list, require_unlocked) + end + end + return filtered_list +end + + +def outfit_is_valid?(outfit_id, physical_files_list, unlocked_list, require_unlocked) + return false if require_unlocked && !unlocked_list.include?(outfit_id) + return physical_files_list.include?(outfit_id) +end + +def add_tags(tags_list=[]) + newTag=pbEnterText("add tag",0,10) + return tags_list if newTag.length == 0 + tags_list << newTag + return tags_list +end + +def get_clothes_by_id(id) + update_global_outfit_lists() + return $PokemonGlobal.clothes_data.has_key?(id) ? $PokemonGlobal.clothes_data[id] : nil +end + +def get_hat_by_id(id) + update_global_outfit_lists() + return $PokemonGlobal.hats_data.has_key?(id) ? $PokemonGlobal.hats_data[id] : nil +end + +def get_hair_by_id(id) + update_global_outfit_lists() + return $PokemonGlobal.hairstyles_data.has_key?(id) ? $PokemonGlobal.hairstyles_data[id] : nil +end + + +def generate_clothes_choice(baseOptions=true,additionalIds=[],additionalTags=[],filterOutTags=[]) + list = [] + list += additionalIds + list += search_clothes(additionalTags) + if baseOptions + list += get_clothes_base_options() + list += search_clothes(get_regional_sets_tags()) + end + return list +end + + +CITY_OUTFIT_TAGS= [ + "pewter","cerulean","vermillion","lavender","celadon","fuchsia","cinnabar", + "crimson","goldenrod","azalea", "violet", "blackthorn", "mahogany", "ecruteak", + "olivine","cianwood", "kin" +] +def list_city_exclusive_clothes() + tags_list = CITY_OUTFIT_TAGS + echoln search_clothes(tags_list) + return search_clothes(tags_list) +end + +def list_city_exclusive_hats() + tags_list = CITY_OUTFIT_TAGS + return search_hats(tags_list) +end + +def list_city_exclusive_hairstyles() + tags_list = CITY_OUTFIT_TAGS + return search_hairstyles(tags_list) +end + +def list_regional_clothes() + selector = OutfitSelector.new + tags_list = selector.get_regional_sets_tags() + return search_clothes(tags_list) +end + +def list_regional_hats() + selector = OutfitSelector.new + tags_list = selector.get_regional_sets_tags() + return search_hats(tags_list) +end + +def list_regional_hairstyles() + selector = OutfitSelector.new + tags_list = selector.get_regional_sets_tags() + return search_hairstyles(tags_list) +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/ItemSets.rb b/Data/Scripts/998_InfiniteFusion/Outfits/ItemSets.rb new file mode 100644 index 000000000..ad2011dff --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/ItemSets.rb @@ -0,0 +1,185 @@ +#set outfit ids, +# + +CLOTHES_NORMAL = "normal" + +CLOTHES_FIGHTING = "fighting" + +CLOTHES_FLYING = "temp" + +CLOTHES_POISON = "deadlypoisondanger" + +CLOTHES_GROUND = "groundcowboy" + +CLOTHES_ROCK = "temp" + +CLOTHES_BUG_1 = "bughakama" +CLOTHES_BUG_2 = "bughakamapants" + +CLOTHES_GHOST = "temp" + +CLOTHES_STEEL_M = "steelworkerM" +CLOTHES_STEEL_F = "steelworkerF" + +CLOTHES_FIRE = "fire" + +CLOTHES_WATER = "waterdress" + +CLOTHES_GRASS = "temp" + +CLOTHES_ELECTRIC = "urbanelectric" + +CLOTHES_PSYCHIC = "temp" + +CLOTHES_ICE = "iceoutfit" + +CLOTHES_DRAGON = "dragonconqueror" + +CLOTHES_DARK = "temp" + +CLOTHES_FAIRY_M = "mikufairym" +CLOTHES_FAIRY_F = "mikufairyf" + + +NORMAL_ITEMS = [:NORMALGEM,:MOOMOOMILK,:POTION,:FULLHEAL,:CHILANBERRY,] +FIGHTING_ITEMS = [:FIGHTINGGEM,:PROTEIN,:CHOPLEBERRY,] +FLYING_ITEMS = [:FLYINGGEM,:HEALTHWING,:MUSCLEWING,:RESISTWING,:GENIUSWING,:CLEVERWING,:SWIFTWING,:AIRBALLOON,:PRETTYWING,:COBABERRY, ] +POISON_ITEMS = [:POISONGEM,:ANTIDOTE, :KEBIABERRY, ] +GROUND_ITEMS = [:GROUNDGEM,:SHUCABERRY, ] +ROCK_ITEMS = [:ROCKGEM, :STARDUST,:CHARTIBERRY, ] +BUG_ITEMS = [:BUGGEM,:HONEY,:TANGABERRY, ] +GHOST_ITEMS = [:GHOSTGEM,:KASIBBERRY,] +STEEL_ITEMS = [:STEELGEM,:BABIRIBERRY,:METALPOWDER,] +FIRE_ITEMS = [:FIREGEM,:LAVACOOKIE,:BURNHEAL,:OCCABERRY, ] +WATER_ITEMS = [:WATERGEM,:HEARTSCALE,:PEARL,:PASSHOBERRY ] +GRASS_ITEMS = [:GRASSGEM,:LUMBERRY,:ORANBERRY,:SITRUSBERRY,:GRASSYSEED,:ABSORBBULB,:TINYMUSHROOM, :RINDOBERRY, ] +ELECTRIC_ITEMS = [:ELECTRICGEM,:ELECTRICSEED,:PARLYZHEAL,:CELLBATTERY,:WACANBERRY, ] +PSYCHIC_ITEMS = [:PSYCHICGEM,:PSYCHICSEED, :MENTALHERB, :PAYAPABERRY,] +ICE_ITEMS = [:ICEGEM,:SNOWBALL,:ICEHEAL,:YACHEBERRY, ] +DRAGON_ITEMS = [:DRAGONGEM,:HABANBERRY, ] +DARK_ITEMS = [:DARKGEM,:COLBURBERRY, ] +FAIRY_ITEMS = [:FAIRYGEM,:MISTYSEED, ] + + +def isWearingElectricOutfit() + return (isWearingClothes(CLOTHES_ELECTRIC)) +end + +def isWearingNormalOutfit() + return (isWearingClothes(CLOTHES_NORMAL)) +end + +def isWearingFightingOutfit() + return (isWearingClothes(CLOTHES_FIGHTING)) +end + +def isWearingFlyingOutfit() + return (isWearingClothes(CLOTHES_FLYING)) +end + +def isWearingPoisonOutfit() + return (isWearingClothes(CLOTHES_POISON)) +end + +def isWearingGroundOutfit() + return (isWearingClothes(CLOTHES_GROUND)) +end + +def isWearingRockOutfit() + return (isWearingClothes(CLOTHES_ROCK)) +end + +def isWearingBugOutfit() + return ((isWearingClothes(CLOTHES_BUG_1) || isWearingClothes(CLOTHES_BUG_2))) +end + +def isWearingGhostOutfit() + return (isWearingClothes(CLOTHES_GHOST)) +end + +def isWearingSteelOutfit() + return ((isWearingClothes(CLOTHES_STEEL_M) || isWearingClothes(CLOTHES_STEEL_F))) +end + +def isWearingFireOutfit() + return (isWearingClothes(CLOTHES_FIRE)) +end + +def isWearingWaterOutfit() + return (isWearingClothes(CLOTHES_WATER)) +end + +def isWearingGrassOutfit() + return (isWearingClothes(CLOTHES_GRASS)) +end + +def isWearingPsychicOutfit() + return (isWearingClothes(CLOTHES_PSYCHIC)) +end + +def isWearingIceOutfit() + return (isWearingClothes(CLOTHES_ICE)) +end + +def isWearingDragonOutfit() + return (isWearingClothes(CLOTHES_DRAGON)) +end + +def isWearingDarkOutfit() + return (isWearingClothes(CLOTHES_DARK)) +end + +def isWearingFairyOutfit() + return ((isWearingClothes(CLOTHES_FAIRY_M) || isWearingClothes(CLOTHES_FAIRY_F))) +end + + + + + +def pickUpTypeItemSetBonus() + return if rand(10) != 0 + items_list = if isWearingElectricOutfit() + ELECTRIC_ITEMS + elsif isWearingNormalOutfit() + NORMAL_ITEMS + elsif isWearingFightingOutfit() + FIGHTING_ITEMS + elsif isWearingFlyingOutfit() + FLYING_ITEMS + elsif isWearingPoisonOutfit() + POISON_ITEMS + elsif isWearingGroundOutfit() + GROUND_ITEMS + elsif isWearingRockOutfit() + ROCK_ITEMS + elsif isWearingBugOutfit() + BUG_ITEMS + elsif isWearingGhostOutfit() + GHOST_ITEMS + elsif isWearingSteelOutfit() + STEEL_ITEMS + elsif isWearingFireOutfit() + FIRE_ITEMS + elsif isWearingWaterOutfit() + WATER_ITEMS + elsif isWearingGrassOutfit() + GRASS_ITEMS + elsif isWearingPsychicOutfit() + PSYCHIC_ITEMS + elsif isWearingIceOutfit() + ICE_ITEMS + elsif isWearingDragonOutfit() + DRAGON_ITEMS + elsif isWearingDarkOutfit() + DARK_ITEMS + elsif isWearingFairyOutfit() + FAIRY_ITEMS + else + [] + end + if !items_list.empty? + Kernel.pbItemBall(items_list.sample) + end +end + diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/OutfitIds.rb b/Data/Scripts/998_InfiniteFusion/Outfits/OutfitIds.rb new file mode 100644 index 000000000..6936d9d82 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/OutfitIds.rb @@ -0,0 +1,148 @@ +#Clothes +CLOTHES_TEAM_ROCKET_MALE = "rocketm" +CLOTHES_TEAM_ROCKET_FEMALE = "rocketf" + +CLOTHES_OFFICE_WORKER_F = "officeworkerf" +CLOTHES_OFFICE_WORKER_M = "officeworkerm" +CLOTHES_BUSINESS_SUIT = "BusinessSuit" + +CLOTHES_ADVENTURER = "fantasyadventurersoutfit" +CLOTHES_EMERALD = "emeraldSPE" +CLOTHES_PIKACHU_ONESIE = "pikaonesie" + +CLOTHES_GLITCH = "glitzerset" +CLOTHES_BREEDER="PKMBreeder" + +CLOTHES_FOSSIL_M ="sado" +CLOTHES_FOSSIL_F ="sada" + +CLOTHES_TREVENANT= "trevenantforestkingcloak" + +CLOTHES_WAITRESS = "maid" +CLOTHES_WAITER = "butler" + +CLOTHES_LASS_YELLOW ="lass" +CLOTHES_LASS_BLUE ="lass2" + +DEFAULT_OUTFIT_MALE = "red" +DEFAULT_OUTFIT_FEMALE = "leaf" +STARTING_OUTFIT = "pikajamas" + + +#Hats +HAT_TEAM_ROCKET = "rocketcap" +HAT_POSTMAN = "postman" +HAT_PIDGEY_NEST = "pidgey" +HAT_SWABLU_NEST = "swablu" +HAT_PIKACHUM_NEST = "pikhatchum" +HAT_PIKACHUF_NEST = "pikhatchuf" +HAT_PARAS_NEST = "headparas" +HAT_EEVEE_NEST = "eevee" + +HAT_PARASHROOM = "parashroom" +HAT_AERODACTYL = "aerodactylSkull" +HAT_DUSKULL_MASK = "duskullmask" +HAT_SLEEPMASK = "sleepmask" +HAT_DITTO_MASK = "creepydittomask" +HAT_EGG = "egg" +HAT_DRIFLOON_CAP = "drifloon" +HAT_EMERALD = "emeraldSPEgem" +HAT_SQUIRTLE_SHADES = "squirtlesquadshades" +HAT_WOOPER = "wooperclips" +HAT_PIKACHU_HOOD = "pikaonesie" +HAT_FEZ = "fez" +HAT_HALO = "halo" +HAT_MAGIKARP = "magicap" +HAT_SLOWKING_SHELL = "slowking" +HAT_ZOROARK = "banefulfoxmask" +HAT_FROG = "froghat" +HAT_SANTA = "santa" +HAT_QMARKS = "glitzerset" +HAT_SUDOWOODO = "sudowoodohorns" + +HAT_TREVENANT="trevenantforestkingcrown" + +HAT_CLOWN = "clownnose" + +HAT_BREEDER_1="breedervisor" +HAT_BREEDER_2="breederbandana" +HAT_BREEDER_2_2="PKMBreeder" + +HAT_BREEDER_3="egg" + +HAT_BREEDEROUTFIT="PKMBreeder" + +HAT_WAITRESS = "maid" + +FUSION_HAT = "fusionnerd" +FUSION_OUTFIT = "fusionnerd" + +HAT_ASH = "ash" +HAT_BIANCA = "bianca" +HAT_CLEFAIRY = "clefairyearheadband" +HAT_FLOWER = "mikufairy" + +HAT_SKITTY_TV = "skittyTV" +HAT_TVHEAD = "tvhead" + +HAT_SCRIBBLES1 = "scribbles1" +HAT_SCRIBBLES2 = "scribbles2" +HAT_SCRIBBLES3 = "scribbles3" +HAT_SCRIBBLES4 = "scribbles4" + +HAT_CARDBOARD_BOX = "box" +HAT_CAPTAIN = "seacaptain" +HAT_GYM_REWARD_1 = "brockpan" +HAT_GYM_REWARD_2 = "starmieclip" +HAT_GYM_REWARD_3 = "surgeglasses" +HAT_GYM_REWARD_4 = "erikaHeadband" +HAT_GYM_REWARD_5 = "kogascarf" +HAT_GYM_REWARD_6 = "sabrinasballs" +HAT_GYM_REWARD_7 = "blaineGlasses" +HAT_GYM_REWARD_8 = "giovannifedora" +HAT_GYM_REWARD_9 = "luluribbon" +HAT_GYM_REWARD_10 = "kurtsentaihelmet" +HAT_GYM_REWARD_11 = "falknerscage" +HAT_GYM_REWARD_12 = "clairbow" +HAT_GYM_REWARD_13 = "chuckmoustache" +HAT_GYM_REWARD_14 = "prycemask" +HAT_GYM_REWARD_15 = "mortyHeadband" +HAT_GYM_REWARD_16 = "magnemitepin" + + +#Hairstyles +HAIR_RED = "red" +HAIR_LEAF = "leaf" + +HAIR_HEXMANIAC = "HexManiac" +HAIR_LASS = "lass" + +HAIR_BALD = "bald" +HAIR_RIVAL = "gary" +HAIR_BROCK = "brock" +HAIR_MISTY1 = "mistyRBY" +HAIR_MISTY2 = "mistyGSC" + +HAIR_SURGE = "surge" #does not exist yet +HAIR_ERIKA = "erika" +HAIR_KOGA = "koga" #does not exist yet +HAIR_JANINE = "janine" +HAIR_SABRINA = "sabrinaGSC" +HAIR_BLAINE = "blaine" #does not exist yet +HAIR_GIOVANNI = "giovanni" #does not exist yet +HAIR_WHITNEY = "whitney" +HAIR_KURT = "kurt" +HAIR_FALKNER = "falkner" +HAIR_CLAIR = "clair" +HAIR_CHUCK = "chuck" #does not exist yet +HAIR_PRYCE = "pryce" #does not exist yet +HAIR_MORTY = "morty" #does not exist yet +HAIR_JASMINE = "jasmine" #does not exist yet + +HAIR_HOOH = "ho-oh" +HAIR_CRESSELIA = "lunarbob" +HAIR_LYCANROC="lycanrocshorthair" +HAIR_HAPPINY="happinysuit" +HAIR_LATIAS="SpecialLatias" +HAIR_GARDEVOIR="gardevoir" +HAIR_EEVEE="eeveetail" \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenu.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenu.rb new file mode 100644 index 000000000..a1c406a27 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenu.rb @@ -0,0 +1,181 @@ +class CharacterSelectionMenuView + attr_accessor :name_sprite + attr_accessor :viewport + attr_accessor :sprites + attr_accessor :textValues + + + OPTIONS_START_Y = 66 + CURSOR_Y_MARGIN = 50 + CURSOR_X_MARGIN = 76 + + CHECKMARK_Y_MARGIN = 20 + CHECKMARK_WIDTH = 50 + + OPTIONS_LABEL_X = 50 + + + OPTIONS_LABEL_WIDTH = 100 + + OPTIONS_VALUE_X = 194 + SELECTOR_X = 120 + SELECTOR_STAGGER_OFFSET=26 + + + ARROW_LEFT_X_POSITION = 75 + ARROW_RIGHT_X_POSITION = 275 + ARROWS_Y_OFFSET = 10#20 + + CONFIRM_X = 296 + CONFIRM_Y= 322 + + STAGGER_OFFSET_1 = 26 + STAGGER_OFFSET_2 = 50 + + + + def initialize + @presenter = CharacterSelectMenuPresenter.new(self) + @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height) + @sprites = {} + @textValues={} + @max_index=5 + end + + def init_graphics() + @sprites["bg"] = IconSprite.new(@viewport) + @sprites["bg"].setBitmap("Graphics/Pictures/trainer_application_form") + + + @sprites["select"] = IconSprite.new(@viewport) + @sprites["select"].setBitmap("Graphics/Pictures/cc_selection_box") + @sprites["select"].x = get_cursor_x_position(0)#OPTIONS_LABEL_X + OPTIONS_LABEL_WIDTH + CURSOR_X_MARGIN + @sprites["select"].y = OPTIONS_START_Y + @sprites["select"].visible = true + + @sprites["leftarrow"] = AnimatedSprite.new("Graphics/Pictures/leftarrow", 8, 40, 28, 2, @viewport) + @sprites["leftarrow"].x = ARROW_LEFT_X_POSITION + @sprites["leftarrow"].y = 0 + @sprites["leftarrow"].visible = false + @sprites["leftarrow"].play + + + @sprites["rightarrow"] = AnimatedSprite.new("Graphics/Pictures/rightarrow", 8, 40, 28, 2, @viewport) + @sprites["rightarrow"].x = ARROW_RIGHT_X_POSITION + @sprites["rightarrow"].y = 0 + @sprites["rightarrow"].visible = false + @sprites["rightarrow"].play + + @presenter.setInitialValues() + end + + def setMaxIndex(maxIndex) + @max_index=maxIndex + end + + def init_labels() + Kernel.pbDisplayText("Confirm", (CONFIRM_X+CURSOR_X_MARGIN), CONFIRM_Y) + + #Labels are directly in the image + + # current_Y = OPTIONS_START_Y + # for option in @presenter.options + # x_pos = option == "Confirm" ? OPTIONS_VALUE_X : OPTIONS_LABEL_X + # + # Kernel.pbDisplayText(option, x_pos, current_Y) + # current_Y += CURSOR_Y_MARGIN + # end + + end + + + + def start + init_graphics() + init_labels() + @presenter.main() + end + + def get_cursor_y_position(index) + return CONFIRM_Y if index == @max_index + return index * CURSOR_Y_MARGIN + OPTIONS_START_Y + end + + def get_cursor_x_position(index) + return CONFIRM_X if index == @max_index + return SELECTOR_X + getTextBoxStaggerOffset(index) + end + + def get_value_x_position(index) + return (OPTIONS_VALUE_X + getTextBoxStaggerOffset(index)) + end + + def getTextBoxStaggerOffset(index) + case index + when 1 + return STAGGER_OFFSET_1 + when 2 + return STAGGER_OFFSET_2 + when 3 + return STAGGER_OFFSET_1 + end + return 0 + end + + + + + def showSideArrows(y_index) + y_position = get_cursor_y_position(y_index) + + @sprites["rightarrow"].y=y_position+ARROWS_Y_OFFSET + @sprites["leftarrow"].y=y_position+ARROWS_Y_OFFSET + + @sprites["leftarrow"].x=getTextBoxStaggerOffset(y_index)+ARROW_LEFT_X_POSITION + @sprites["rightarrow"].x= getTextBoxStaggerOffset(y_index)+ARROW_RIGHT_X_POSITION + + @sprites["rightarrow"].visible=true + @sprites["leftarrow"].visible=true + end + + def hideSideArrows() + @sprites["rightarrow"].visible=false + @sprites["leftarrow"].visible=false + end + + def displayAge(age,y_index) + y_position = get_cursor_y_position(y_index) + x_position = get_value_x_position(y_index) + Kernel.pbClearNumber() + Kernel.pbDisplayNumber(age,x_position,y_position) + end + + def displayText(spriteId,text,y_index) + @textValues[spriteId].dispose if @textValues[spriteId] + yposition = get_cursor_y_position(y_index) + xposition = get_value_x_position(y_index) + + baseColor= baseColor ? baseColor : Color.new(72,72,72) + shadowColor= shadowColor ? shadowColor : Color.new(160,160,160) + @textValues[spriteId] = BitmapSprite.new(Graphics.width,Graphics.height,@viewport) + text1=_INTL(text) + textPosition=[ + [text1,xposition,yposition,2,baseColor,shadowColor], + ] + pbSetSystemFont(@textValues[spriteId].bitmap) + pbDrawTextPositions(@textValues[spriteId].bitmap,textPosition) + + end + + + def updateGraphics() + Graphics.update + Input.update + if @sprites + @sprites["rightarrow"].update + @sprites["leftarrow"].update + end + end + + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenuPresenter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenuPresenter.rb new file mode 100644 index 000000000..af9d9ff22 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/CharacterSelectMenuPresenter.rb @@ -0,0 +1,275 @@ +class CharacterSelectMenuPresenter + attr_accessor :options + attr_reader :current_index + + OPTION_NAME = 'Name' + OPTION_AGE = "Age" + OPTION_GENDER = "Gender" + OPTION_HAIR = "Hair" + OPTION_SKIN = "Skin" + OPTION_CONFIRM = "Confirm" + + MIN_AGE = 10 + MAX_AGE = 17 + DEFAULT_NAMES = ["Green", "Red"] + + MIN_SKIN_COLOR = 1 + MAX_SKIN_COLOR = 6 + SKIN_COLOR_IDS = ["Type A", "Type B", "Type C", "Type D", "Type E", "Type F"] + GENDERS_IDS = ["Female", "Male"] + + HAIR_COLOR_IDS = [1, 2, 3, 4] + HAIR_COLOR_NAMES = ["Blonde", "Light Brown", "Dark Brown", "Black"] + + #ids for displayed text sprites + NAME_TEXT_ID = "name" + HAIR_TEXT_ID = "hair" + SKIN_TEXT_ID = "skin" + + def initialize(view) + @view = view + + @gender = 1 + @age = MIN_AGE + @name = "" + @skinTone = 5 + @hairstyle = "red" + @hairColor = 2 + + @options = [OPTION_NAME, OPTION_GENDER, OPTION_AGE, OPTION_SKIN, OPTION_HAIR, OPTION_CONFIRM] + + @trainerPreview = TrainerClothesPreview.new(300, 80, false, "POKEBALL") + @trainerPreview.show() + @closed = false + @current_index = 0 + @view.setMaxIndex(@options.length - 1) + end + + def main() + pbSEPlay("GUI naming tab swap start", 80, 100) + @current_index = 0 + loop do + @view.updateGraphics() + if Input.trigger?(Input::DOWN) + @current_index = move_menu_vertical(1) + elsif Input.trigger?(Input::UP) + @current_index = move_menu_vertical(-1) + elsif Input.trigger?(Input::RIGHT) + move_menu_horizontal(@current_index, 1) + elsif Input.trigger?(Input::LEFT) + move_menu_horizontal(@current_index, -1) + elsif Input.trigger?(Input::ACTION) || Input.trigger?(Input::USE) + action_button_pressed(@current_index) + end + break if @closed + end + end + + def updateTrainerPreview + @trainerPreview.resetOutfits + @trainerPreview.updatePreview + end + + def action_button_pressed(current_index) + selected_option = @options[current_index] + case selected_option + when OPTION_NAME + pbSEPlay("GUI summary change page", 80, 100) + @name = pbEnterPlayerName(_INTL("Enter your name"), 0, Settings::MAX_PLAYER_NAME_SIZE) + @name = getDefaultName() if @name == '' + pbSEPlay("GUI trainer card open", 80, 100) + updateDisplayedName(current_index) + applyHair() #for easter egg lol + when OPTION_CONFIRM + pbSEPlay("GUI save choice", 80, 100) + @current_index = @options.length - 1 + update_cursor(@current_index) + @name = getDefaultName if @name == "" + updateDisplayedName(getOptionIndex(OPTION_NAME)) + cmd = pbMessage("Is this information correct?", [_INTL("Yes"), _INTL("No")]) + if cmd == 0 + pbSEPlay("GUI naming confirm", 80, 100) + #pbMessage("You will be able to customize your appearance further while playing") + applyAllSelectedValues() + close_menu() + end + else + pbSEPlay("GUI save choice", 80, 100) + @current_index = @options.length - 1 + update_cursor(@current_index) + @name = getDefaultName if @name == "" + updateDisplayedName(getOptionIndex(OPTION_NAME)) + end + end + + def getDefaultName() + return DEFAULT_NAMES[@gender] + end + + def updateDisplayedName(current_index) + @view.displayText(NAME_TEXT_ID, @name, current_index) + end + + def applyAllSelectedValues + applyGender(@gender) + echoln @age + pbSet(VAR_TRAINER_AGE, @age) + $Trainer.skin_tone = @skinTone + $Trainer.name = @name + end + + def getOptionIndex(option_name) + i = 0 + for option in @options + return i if option == option_name + i += 1 + end + return -1 + end + + #VERTICAL NAVIGATION + + def move_menu_vertical(offset) + pbSEPlay("GUI sel decision", 80, 100) + @current_index += offset + @current_index = 0 if @current_index > @options.length - 1 + @current_index = @options.length - 1 if @current_index <= -1 + + update_cursor(@current_index) + return @current_index + end + + def update_cursor(index) + @view.sprites["select"].y = @view.get_cursor_y_position(index) + @view.sprites["select"].x = @view.get_cursor_x_position(index) + + set_custom_cursor(index) + end + + def close_menu + @trainerPreview.erase() + Kernel.pbClearNumber() + Kernel.pbClearText() + pbDisposeSpriteHash(@view.sprites) + pbDisposeSpriteHash(@view.textValues) + @closed = true + end + + def set_custom_cursor(index) + selected_option = @options[index] + case selected_option + when OPTION_GENDER + @view.showSideArrows(index) + when OPTION_AGE + @view.showSideArrows(index) + when OPTION_HAIR + @view.showSideArrows(index) + when OPTION_SKIN + @view.showSideArrows(index) + else + @view.hideSideArrows + end + end + + #HORIZONTAL NAVIGATION + def move_menu_horizontal(current_index, incr) + pbSEPlay("GUI sel cursor", 80, 100) + selected_option = @options[current_index] + case selected_option + when OPTION_GENDER then + setGender(current_index, incr) + when OPTION_HAIR then + setHairColor(current_index, incr) + when OPTION_SKIN then + setSkinColor(current_index, incr) + when OPTION_AGE then + setAge(current_index, incr) + end + updateTrainerPreview() + end + + def setGender(current_index, incr) + @gender += incr + @gender = 0 if @gender >= 2 + @gender = 1 if @gender <= -1 + applyGender(@gender) + label = GENDERS_IDS[@gender] + @view.displayText(GENDERS_IDS, label, current_index) + end + + def setSkinColor(current_index, incr) + @skinTone += incr + @skinTone = MIN_SKIN_COLOR if @skinTone > MAX_SKIN_COLOR + @skinTone = MAX_SKIN_COLOR if @skinTone < MIN_SKIN_COLOR + $Trainer.skin_tone = @skinTone + label = SKIN_COLOR_IDS[@skinTone - 1] + @view.displayText(SKIN_TEXT_ID, label, current_index) + end + + def setHairColor(current_index, incr) + max_id = HAIR_COLOR_IDS.length - 1 + @hairColor += incr + @hairColor = 0 if @hairColor > max_id + @hairColor = max_id if @hairColor <= -1 + applyHair() + @view.displayText(HAIR_TEXT_ID, HAIR_COLOR_NAMES[@hairColor], current_index) + end + + def applyHair() + applyHairEasterEggs() + hairColorId = HAIR_COLOR_IDS[@hairColor] + hairId = hairColorId.to_s + "_" + @hairstyle.to_s + $Trainer.hair = hairId + end + + def applyHairEasterEggs() + @hairstyle = HAIR_RIVAL if @name == "Gary" && @gender == 1 + @hairstyle = HAIR_BROCK if @name == "Brock" && @gender == 1 + @hairstyle = HAIR_MISTY1 if @name == "Misty" && @gender == 0 + + end + + def applyGender(gender_index) + # outfitId = gender + 1 + pbSet(VAR_TRAINER_GENDER, gender_index) + + outfitId = get_outfit_id_from_index(gender_index) + @hairstyle = outfitId + applyHair() + #$Trainer.hair = outfitId + $Trainer.clothes = outfitId + $Trainer.hat = outfitId + end + + def get_outfit_id_from_index(gender_index) + if gender_index == 1 #Male + return "red" + else + #Female + return "leaf" + end + end + + #AGE + def setAge(y_index, incr) + @age += incr + @age = MIN_AGE if @age > MAX_AGE + @age = MAX_AGE if @age < MIN_AGE + + @view.displayAge(@age, y_index) + end + + def setInitialValues() + genderIndex = getOptionIndex(OPTION_GENDER) + hairIndex = getOptionIndex(OPTION_HAIR) + skinIndex = getOptionIndex(OPTION_SKIN) + ageIndex = getOptionIndex(OPTION_AGE) + + setGender(genderIndex, 0) + setAge(ageIndex, 0) + setHairColor(hairIndex, 0) + setSkinColor(skinIndex, 0) + updateTrainerPreview() + end + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/LayeredClothes_Menus.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/LayeredClothes_Menus.rb new file mode 100644 index 000000000..e937a59fd --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/LayeredClothes_Menus.rb @@ -0,0 +1,265 @@ +def playOutfitRemovedAnimation() + pbSEPlay("shiny", 80, 60) + $scene.spriteset.addUserAnimation(Settings::OW_SHINE_ANIMATION_ID, $game_player.x, $game_player.y, true) +end + +def playOutfitChangeAnimation() + pbSEPlay("shiny", 80, 100) + $scene.spriteset.addUserAnimation(Settings::OW_SHINE_ANIMATION_ID, $game_player.x, $game_player.y, true) +end + +def selectHairstyle(all_unlocked = false) + selector = OutfitSelector.new + display_outfit_preview() + hat = $Trainer.hat + commands = ["Next style", "Previous style", "Toggle hat", "Back"] + previous_input = 0 + # To enable turning the common event that lets you turn around while in the dialog box + while (true) + choice = pbShowCommands(nil, commands, commands.length, previous_input) + previous_input = choice + case choice + when 0 #NEXT + playOutfitChangeAnimation() + selector.changeToNextHairstyle(1, all_unlocked) + display_outfit_preview() + when 1 #PREVIOUS + playOutfitChangeAnimation() + selector.changeToNextHairstyle(-1, all_unlocked) + display_outfit_preview() + when 2 #Toggle hat + pbSEPlay("GUI storage put down", 80, 100) + if hat == $Trainer.hat + $Trainer.hat = nil + else + $Trainer.hat = hat + end + display_outfit_preview() + else + break + end + end + hide_outfit_preview() + $Trainer.hat = hat +end + +def swapToNextHairVersion() + split_hair = getSplitHairFilenameAndVersionFromID($Trainer.hair) + hair_version = split_hair[0] + hair_style = split_hair[1] + current_version = hair_version + pbSEPlay("GUI party switch", 80, 100) + newVersion = current_version.to_i + 1 + lastVersion = findLastHairVersion(hair_style) + newVersion = lastVersion if newVersion <= 0 + newVersion = 1 if newVersion > lastVersion + $Trainer.hair = getFullHairId(hair_style,newVersion) +end + +def selectHairColor + original_color = $Trainer.hair_color + original_hair = $Trainer.hair + $game_switches[SWITCH_SELECTING_CLOTHES]=true + $game_map.update + display_outfit_preview() + hat = $Trainer.hat + commands = ["Swap base color", "Shift up", "Shift down", "Toggle hat", "Remove dye", "Confirm", "Never Mind"] + previous_input = 0 + + while (true) + choice = pbShowCommands(nil, commands, commands.length, previous_input) + previous_input = choice + case choice + when 0 #change base + swapToNextHairVersion() + display_outfit_preview() + ret = false + when 1 #NEXT + #playOutfitChangeAnimation() + pbSEPlay("GUI storage pick up", 80, 100) + shiftHairColor(10) + display_outfit_preview() + ret = true + when 2 #PREVIOUS + pbSEPlay("GUI storage pick up", 80, 100) + shiftHairColor(-10) + display_outfit_preview() + ret = true + when 3 #Toggle hat + pbSEPlay("GUI storage put down", 80, 100) + if hat == $Trainer.hat + $Trainer.hat = nil + else + $Trainer.hat = hat + end + display_outfit_preview() + when 4 #Reset + pbSEPlay("GUI storage put down", 80, 100) + $Trainer.hair_color = 0 + display_outfit_preview() + ret = false + when 5 #Confirm + break + else + $Trainer.hair_color = original_color + $Trainer.hair = original_hair + ret = false + break + end + end + hide_outfit_preview() + $Trainer.hat = hat + $game_switches[SWITCH_SELECTING_CLOTHES]=false + $game_map.update + return ret + +end + +def selectHatColor(secondary_hat=false) + original_color = secondary_hat ? $Trainer.hat2_color : $Trainer.hat_color + display_outfit_preview() + commands = ["Shift up", "Shift down", "Reset", "Confirm", "Never Mind"] + previous_input = 0 + while (true) + choice = pbShowCommands(nil, commands, commands.length, previous_input) + previous_input = choice + case choice + when 0 #NEXT + pbSEPlay("GUI storage pick up", 80, 100) + shiftHatColor(10,secondary_hat) + display_outfit_preview + ret = true + when 1 #PREVIOUS + pbSEPlay("GUI storage pick up", 80, 100) + shiftHatColor(-10,secondary_hat) + display_outfit_preview + ret = true + when 2 #Reset + pbSEPlay("GUI storage put down", 80, 100) + $Trainer.hat_color = 0 if !secondary_hat + $Trainer.hat2_color = 0 if secondary_hat + display_outfit_preview + refreshPlayerOutfit + ret = false + when 3 #Confirm + break + else + $Trainer.hat_color = original_color if !secondary_hat + $Trainer.hat2_color = original_color if secondary_hat + ret = false + break + end + end + refreshPlayerOutfit() + hide_outfit_preview() + return ret +end + +def selectClothesColor + original_color = $Trainer.clothes_color + display_outfit_preview() + commands = ["Shift up", "Shift down", "Reset", "Confirm", "Never Mind"] + previous_input = 0 + ret = false + while (true) + choice = pbShowCommands(nil, commands, commands.length, previous_input) + previous_input = choice + case choice + when 0 #NEXT + pbSEPlay("GUI storage pick up", 80, 100) + shiftClothesColor(10) + display_outfit_preview() + ret = true + when 1 #PREVIOUS + pbSEPlay("GUI storage pick up", 80, 100) + shiftClothesColor(-10) + display_outfit_preview() + ret = true + when 2 #Reset + pbSEPlay("GUI storage pick up", 80, 100) + $Trainer.clothes_color = 0 + display_outfit_preview() + refreshPlayerOutfit() + ret = false + when 3 #Confirm + break + else + $Trainer.clothes_color = original_color + ret = false + break + end + end + refreshPlayerOutfit() + hide_outfit_preview() + return ret +end + +def selectHat(all_unlocked = false) + selector = OutfitSelector.new + display_outfit_preview() + commands = ["Next hat", "Previous hat", "Remove hat", "Back"] + previous_input = 0 + while (true) + choice = pbShowCommands(nil, commands, commands.length, previous_input) + previous_input = choice + case choice + when 0 #NEXT + playOutfitChangeAnimation() + selector.changeToNextHat(1, all_unlocked) + display_outfit_preview() + when 1 #PREVIOUS + playOutfitChangeAnimation() + selector.changeToNextHat(-1, all_unlocked) + display_outfit_preview() + when 2 #REMOVE HAT + playOutfitRemovedAnimation() + $Trainer.hat = nil + selector.display_outfit_preview() + else + break + end + end + hide_outfit_preview() +end + +def spinCharacter + pbSEPlay("GUI party switch", 80, 100) + +end + +def selectClothes(all_unlocked = false) + selector = OutfitSelector.new + display_outfit_preview() + commands = ["Next", "Previous"] + #commands << "Remove clothes (DEBUG)" if $DEBUG + commands << "Remove" if $DEBUG + commands << "Back" + previous_input = 0 + while (true) + choice = pbShowCommands(nil, commands, commands.length, previous_input) + previous_input = choice + case choice + when 0 #NEXT + playOutfitChangeAnimation() + selector.changeToNextClothes(1, all_unlocked) + display_outfit_preview() + when 1 #PREVIOUS + playOutfitChangeAnimation() + selector.changeToNextClothes(-1, all_unlocked) + display_outfit_preview() + when 2 #REMOVE CLOTHES + break if !$DEBUG + playOutfitRemovedAnimation() + $Trainer.clothes = nil + display_outfit_preview() + else + break + end + end + hide_outfit_preview() +end + +def place_hat_on_pokemon(pokemon) + hatscreen = PokemonHatPresenter.new(nil, pokemon) + hatscreen.pbStartScreen() +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenPresenter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenPresenter.rb new file mode 100644 index 000000000..9c8a85b7f --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenPresenter.rb @@ -0,0 +1,103 @@ +class PokemonHatPresenter + PIXELS_PER_MOVEMENT = 4 + + def initialize(view, pokemon) + @view = view + @pokemon = pokemon + @hatFilename = "Graphics/Characters/player/hat/trainer/hat_trainer_1" + @sprites = {} + + @x_pos = pokemon.hat_x ? pokemon.hat_x : 0 + @y_pos = pokemon.hat_y ? pokemon.hat_y : 0 + @hat_id = pokemon.hat ? pokemon.hat : 1 + @viewport = nil + @previewwindow = nil + + @original_pokemon_bitmap = nil + end + + def pbStartScreen + @view.init_window(self) + cancel if !select_hat() + if position_hat() + updatePokemonHatPosition() + else + cancel + end + @view.hide_move_arrows + @view.hide_select_arrows + @view.dispose_window() + end + + def updatePokemonHatPosition() + @pokemon.hat = @hat_id + @pokemon.hat_x = @x_pos + @pokemon.hat_y = @y_pos + end + + def cancel + @pokemon.hat = nil + end + + def select_hat + selector = OutfitSelector.new + @view.display_select_arrows + outfit_type_path = get_hats_sets_list_path() + @pokemon.hat = 0 if !@pokemon.hat + loop do + Graphics.update + Input.update + @hat_id = selector.selectNextOutfit(@hat_id, 1, selector.hats_list, [], false, "hat",$Trainer.unlocked_hats,false) if Input.trigger?(Input::RIGHT) + @hat_id = selector.selectNextOutfit(@hat_id, -1, selector.hats_list, [], false, "hat",$Trainer.unlocked_hats,false) if Input.trigger?(Input::LEFT) + break if Input.trigger?(Input::USE) + return false if Input.trigger?(Input::BACK) + @view.update() + end + @pokemon.hat = @hat_id + @view.hide_select_arrows + + end + + def position_hat + @view.display_move_arrows + min_x, max_x = -64, 88 + min_y, max_y = -20, 140 + loop do + Graphics.update + Input.update + @x_pos += PIXELS_PER_MOVEMENT if Input.repeat?(Input::RIGHT) && @x_pos < max_x + @x_pos -= PIXELS_PER_MOVEMENT if Input.repeat?(Input::LEFT) && @x_pos > min_x + @y_pos += PIXELS_PER_MOVEMENT if Input.repeat?(Input::DOWN) && @y_pos < max_y + @y_pos -= PIXELS_PER_MOVEMENT if Input.repeat?(Input::UP) && @y_pos > min_y + break if Input.trigger?(Input::USE) + return false if Input.trigger?(Input::BACK) + @view.update() + end + @view.hide_move_arrows + return true + end + + def initialize_bitmap() + spriteLoader = BattleSpriteLoader.new + + if @pokemon.isTripleFusion? + #todo + elsif @pokemon.isFusion? + @original_pokemon_bitmap = spriteLoader.load_fusion_sprite(@pokemon.head_id(),@pokemon.body_id()) + else + echoln @pokemon + echoln @pokemon.species_data + @original_pokemon_bitmap = spriteLoader.load_base_sprite(@pokemon.id_number) + end + @original_pokemon_bitmap.scale_bitmap(Settings::FRONTSPRITE_SCALE) + end + + def getPokemonHatBitmap() + @hatFilename = getTrainerSpriteHatFilename(@hat_id) + hatBitmapWrapper = AnimatedBitmap.new(@hatFilename, 0) if pbResolveBitmap(@hatFilename) + pokemon_bitmap = @original_pokemon_bitmap.bitmap.clone + pokemon_bitmap.blt(@x_pos, @y_pos, hatBitmapWrapper.bitmap, hatBitmapWrapper.bitmap.rect) if hatBitmapWrapper + return pokemon_bitmap + end + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenView.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenView.rb new file mode 100644 index 000000000..68a504cdc --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/PokemonHatScreenView.rb @@ -0,0 +1,139 @@ +class PokemonHatView + WINDOW_POS_X = Graphics.width / 4 + WINDOW_POS_Y = Graphics.height / 8 + + attr_accessor :x_pos + attr_accessor :y_pos + + def initialize(x_pos = nil, y_pos = nil, windowed = true) + @x_pos = x_pos ? x_pos : WINDOW_POS_X + @y_pos = y_pos ? y_pos : WINDOW_POS_Y + @windowed = windowed + + end + + def init_window(presenter) + @presenter = presenter + + + presenter.initialize_bitmap() + pokemon_bitmap = presenter.getPokemonHatBitmap() + + @previewwindow = PictureWindow.new(pokemon_bitmap) + @previewwindow.opacity = 0 if !@windowed + update_window_position() + @previewwindow.z = 9999999 + + @viewport = Viewport.new(@previewwindow.x, @previewwindow.y, @previewwindow.width, @previewwindow.height) + @viewport.z = 9999999 + @sprites = {} + + initialize_arrows() + + end + + def getWindowWidth() + return @previewwindow.width/2 + end + + def initialize_arrows() + middle_horizontal = 100 + width_horizontal = 90 + + middle_vertical = 100 + width_vertical = 90 + + @sprites["uparrow"] = AnimatedSprite.new("Graphics/Pictures/uparrow", 8, 28, 40, 2, @viewport) + @sprites["uparrow"].x = middle_horizontal + @sprites["uparrow"].y = middle_vertical - width_vertical + @sprites["uparrow"].z = 100 + @sprites["uparrow"].visible=true + + + @sprites["downarrow"] = AnimatedSprite.new("Graphics/Pictures/downarrow", 8, 28, 40, 2, @viewport) + @sprites["downarrow"].x = middle_horizontal + @sprites["downarrow"].y = middle_vertical + width_vertical + + @sprites["leftarrow"] = AnimatedSprite.new("Graphics/Pictures/leftarrow", 8, 40, 28, 2, @viewport) + @sprites["leftarrow"].x = middle_horizontal - width_horizontal -10 + @sprites["leftarrow"].y = middle_vertical + + + @sprites["rightarrow"] = AnimatedSprite.new("Graphics/Pictures/rightarrow", 8, 40, 28, 2, @viewport) + @sprites["rightarrow"].x = middle_horizontal + width_horizontal + @sprites["rightarrow"].y = middle_vertical + + @sprites["uparrow"].visible=false + @sprites["downarrow"].visible=false + @sprites["leftarrow"].visible=false + @sprites["rightarrow"].visible=false + + end + + def update_window_position() + @previewwindow.x = @x_pos + @previewwindow.y = @y_pos + end + + #TODO + def display_select_arrows + hide_move_arrows + @sprites["rightarrow"].visible=true + @sprites["leftarrow"].visible=true + + @sprites["rightarrow"].play + @sprites["leftarrow"].play + end + + def hide_select_arrows + @sprites["rightarrow"].visible=false + @sprites["leftarrow"].visible=false + @sprites["rightarrow"].stop + @sprites["leftarrow"].stop + @sprites["rightarrow"].reset + @sprites["leftarrow"].reset + end + + def display_move_arrows + hide_move_arrows + @sprites["rightarrow"].visible=true + @sprites["leftarrow"].visible=true + @sprites["uparrow"].visible=true + @sprites["downarrow"].visible=true + + @sprites["rightarrow"].play + @sprites["leftarrow"].play + @sprites["uparrow"].play + @sprites["downarrow"].play + end + + def hide_move_arrows + @sprites["rightarrow"].visible=false + @sprites["leftarrow"].visible=false + @sprites["uparrow"].visible=false + @sprites["downarrow"].visible=false + + @sprites["rightarrow"].stop + @sprites["leftarrow"].stop + @sprites["uparrow"].stop + @sprites["downarrow"].stop + end + + def dispose_window + @previewwindow.dispose + @viewport.dispose + pbDisposeSpriteHash(@sprites) + @sprites = nil + end + + def update + @sprites["rightarrow"].update + @sprites["leftarrow"].update + @sprites["uparrow"].update + @sprites["downarrow"].update + + @previewwindow.clearBitmaps + @previewwindow.setBitmap(@presenter.getPokemonHatBitmap()) + @previewwindow.update + end +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/TrainerClothesPreview.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/TrainerClothesPreview.rb new file mode 100644 index 000000000..1f0c0eb18 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/TrainerClothesPreview.rb @@ -0,0 +1,72 @@ +class TrainerClothesPreview + attr_writer :pokeball, :clothes, :hat, :hat2, :hair, :skin_tone, :hair_color, :hat_color,:hat2_color, :clothes_color + + def initialize(x = 0, y = 0, windowed = true, pokeball = nil) + @playerBitmap = nil + @playerSprite = nil + @x_pos = x + @y_pos = y + @windowed = windowed + + @pokeball = pokeball + resetOutfits() + end + + def set_hat(value,is_secondaryHat=false) + if is_secondaryHat + @hat2 = value + else + @hat = value + end + end + + def set_hat_color(value,is_secondaryHat=false) + if is_secondaryHat + @hat2_color = value + else + @hat_color = value + end + end + + def resetOutfits() + @clothes = $Trainer.clothes + @hat = $Trainer.hat + @hat2 = $Trainer.hat2 + @hair = $Trainer.hair + @skin_tone = $Trainer.skin_tone + @hair_color = $Trainer.hair_color + @hat_color = $Trainer.hat_color + @hat2_color = $Trainer.hat2_color + @clothes_color = $Trainer.clothes_color + end + + def show() + @playerBitmap = generate_front_trainer_sprite_bitmap(false, + @pokeball, + @clothes, + @hat,@hat2, @hair, + @skin_tone, + @hair_color, @hat_color, @clothes_color, @hat2_color) + initialize_preview() + end + + def updatePreview() + erase() + show() + end + + def initialize_preview() + @playerSprite = PictureWindow.new(@playerBitmap) + @playerSprite.opacity = 0 if !@windowed + + @playerSprite.x = @x_pos + @playerSprite.y = @y_pos + @playerSprite.z = 9999 + @playerSprite.update + end + + def erase() + @playerSprite.dispose if @playerSprite + end + +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/0_OutfitsMartAdapter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/0_OutfitsMartAdapter.rb new file mode 100644 index 000000000..8ae856d56 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/0_OutfitsMartAdapter.rb @@ -0,0 +1,159 @@ +class OutfitsMartAdapter < PokemonMartAdapter + attr_accessor :worn_clothes + attr_accessor :is_secondary_hat + attr_accessor :items + + WORN_ITEM_BASE_COLOR = MessageConfig::BLUE_TEXT_MAIN_COLOR + WORN_ITEM_SHADOW_COLOR = MessageConfig::BLUE_TEXT_SHADOW_COLOR + + + REGIONAL_SET_BASE_COLOR = Color.new(76,72,104) + REGIONAL_SET_SHADOW_COLOR = Color.new(173,165,189) + + CITY_EXCLUSIVE_BASE_COLOR = Color.new(61 , 125, 70) #Color.new(72 , 104, 83) + CITY_EXCLUSIVE_SHADOW_COLOR = Color.new(165, 189, 178) + + def initialize(stock = [], isShop = true, isSecondaryHat = false) + @is_secondary_hat = isSecondaryHat + @items = stock + @worn_clothes = get_current_clothes() + @isShop = isShop + @version = nil + $Trainer.dyed_hats = {} if !$Trainer.dyed_hats + $Trainer.dyed_clothes = {} if !$Trainer.dyed_clothes + + #todo: refactor to get the list from the first search when + # setting the stock instead of searching twice + @regional_set_items = @isShop ? list_regional_set_items : [] + @city_exclusive_items = @isShop ? list_city_exclusive_items : [] + end + + def list_regional_set_items() + return [] + end + + def list_city_exclusive_items() + return [] + end + + def getDisplayName(item) + return getName(item) if !item.name + name = item.name + name = "* #{name}" if is_wearing_clothes(item.id) + return name + end + + def is_wearing_clothes(outfit_id) + return outfit_id == @worn_clothes + end + + def player_changed_clothes?() + return false + #implement in inheriting classes + end + + def toggleText() + return "" + end + + def switchVersion(item,delta=1) + return + end + + def toggleEvent(item) + return + end + + def isWornItem?(item) + return false + end + + def isShop?() + return @isShop + end + + def getPrice(item, selling = nil) + return 0 if !@isShop + return nil if itemOwned(item) + return item.price.to_i + end + + def getDisplayPrice(item, selling = nil) + return "" if !@isShop + return "-" if itemOwned(item) + super + end + + def updateStock() + updated_items = [] + for item in @items + updated_items << item if !get_unlocked_items_list().include?(item.id) + end + @items = updated_items + end + + def removeItem(item) + super + end + + def itemOwned(item) + owned_list = get_unlocked_items_list() + return owned_list.include?(item.id) + end + + def canSell?(item) + super + end + + def isItemInRegionalSet(item) + return @regional_set_items.include?(item.id) + end + + def isItemCityExclusive(item) + return @city_exclusive_items.include?(item.id) + end + + def getBaseColorOverride(item) + return REGIONAL_SET_BASE_COLOR if isItemInRegionalSet(item) + return CITY_EXCLUSIVE_BASE_COLOR if isItemCityExclusive(item) + return nil + end + + def getShadowColorOverride(item) + return REGIONAL_SET_SHADOW_COLOR if isItemInRegionalSet(item) + return CITY_EXCLUSIVE_SHADOW_COLOR if isItemCityExclusive(item) + return nil + end + + def getMoney + super + end + + def getMoneyString + super + end + + def setMoney(value) + super + end + + def getItemIconRect(_item) + super + end + + def getQuantity(item) + super + end + + def showQuantity?(item) + super + end + + def updateVersion(item) + @version = 1 if !currentVersionExists?(item) + end + + def currentVersionExists?(item) + return true + end +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesMartAdapter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesMartAdapter.rb new file mode 100644 index 000000000..c28c2bc01 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesMartAdapter.rb @@ -0,0 +1,116 @@ +class ClothesMartAdapter < OutfitsMartAdapter + + DEFAULT_NAME = "[unknown]" + DEFAULT_DESCRIPTION = "A piece of clothing that trainers can wear." + def toggleEvent(item) + if !isShop? && $Trainer.clothes_color != 0 + if pbConfirmMessage(_INTL("Would you like to remove the dye?")) + $Trainer.clothes_color = 0 + end + end + end + + def list_regional_set_items() + return list_regional_clothes + end + + def list_city_exclusive_items + return list_city_exclusive_clothes + end + + def initialize(stock = nil, isShop = nil) + super + end + + def getName(item) + name= item.id + name = "* #{name}" if is_wearing_clothes(item.id) + return name + end + + def getDescription(item) + return DEFAULT_DESCRIPTION if !item.description + return item.description + end + + def getItemIcon(item) + return Settings::BACK_ITEM_ICON_PATH if !item + return getOverworldOutfitFilename(item.id) + end + + def updateTrainerPreview(item, previewWindow) + return if !item + previewWindow.clothes = item.id + $Trainer.clothes = item.id + set_dye_color(item,previewWindow) + + pbRefreshSceneMap + previewWindow.updatePreview() + end + + def get_dye_color(item_id) + return 0 if isShop? + $Trainer.dyed_clothes= {} if ! $Trainer.dyed_clothes + if $Trainer.dyed_clothes.include?(item_id) + return $Trainer.dyed_clothes[item_id] + end + return 0 + end + + def set_dye_color(item,previewWindow) + if !isShop? + $Trainer.dyed_clothes= {} if ! $Trainer.dyed_clothes + if $Trainer.dyed_clothes.include?(item.id) + dye_color = $Trainer.dyed_clothes[item.id] + $Trainer.clothes_color = dye_color + previewWindow.clothes_color = dye_color + else + $Trainer.clothes_color=0 + previewWindow.clothes_color=0 + end + else + $Trainer.clothes_color=0 + previewWindow.clothes_color=0 + end + end + + def addItem(item) + changed_clothes = obtainClothes(item.id) + if changed_clothes + @worn_clothes = item.id + end + end + + def get_current_clothes() + return $Trainer.clothes + end + + def player_changed_clothes?() + $Trainer.clothes != @worn_clothes + end + + def putOnSelectedOutfit() + putOnClothes($Trainer.clothes) + @worn_clothes = $Trainer.clothes + end + + def putOnOutfit(item) + putOnClothes(item.id) if item + @worn_clothes = item.id if item + end + + def reset_player_clothes() + $Trainer.clothes = @worn_clothes + $Trainer.clothes_color = $Trainer.dyed_clothes[@worn_clothes] if $Trainer.dyed_clothes && $Trainer.dyed_clothes[@worn_clothes] + end + + def get_unlocked_items_list() + return $Trainer.unlocked_clothes + end + + def isWornItem?(item) + super + end + + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShop.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShop.rb new file mode 100644 index 000000000..fa7d5d72b --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShop.rb @@ -0,0 +1,146 @@ +def genericOutfitsShopMenu(stock = [], itemType = nil, versions = false, isShop=true, message=nil) + commands = [] + commands[cmdBuy = commands.length] = _INTL("Buy") + commands[cmdQuit = commands.length] = _INTL("Quit") + message = _INTL("Welcome! How may I serve you?") if !message + cmd = pbMessage(message, commands, cmdQuit + 1) + loop do + if cmdBuy >= 0 && cmd == cmdBuy + adapter = getAdapter(itemType, stock, isShop) + view = ClothesShopView.new() + presenter = getPresenter(itemType, view, stock, adapter, versions) + presenter.pbBuyScreen + break + else + pbMessage(_INTL("Please come again!")) + break + end + end +end + + + +def getPresenter(itemType, view, stock, adapter, versions) + case itemType + when :HAIR + return HairShopPresenter.new(view, stock, adapter, versions) + else + return ClothesShopPresenter.new(view, stock, adapter, versions) + end +end + +def getAdapter(itemType, stock, isShop, is_secondary=false) + case itemType + when :CLOTHES + return ClothesMartAdapter.new(stock, isShop) + when :HAT + return HatsMartAdapter.new(stock, isShop,is_secondary) + when :HAIR + return HairMartAdapter.new(stock, isShop) + end +end + +def list_all_possible_outfits() end + +def clothesShop(outfits_list = [], free=false,customMessage=nil) + stock = [] + outfits_list.each { |outfit_id| + outfit = get_clothes_by_id(outfit_id) + stock << outfit if outfit + } + genericOutfitsShopMenu(stock, :CLOTHES,false,!free,customMessage) +end + +def hatShop(outfits_list = [], free=false, customMessage=nil) + stock = [] + outfits_list.each { |outfit_id| + outfit = get_hat_by_id(outfit_id) + stock << outfit if outfit + } + genericOutfitsShopMenu(stock, :HAT,false,!free,customMessage) +end + +def hairShop(outfits_list = [],free=false, customMessage=nil) + currentHair = getSimplifiedHairIdFromFullID($Trainer.hair) + stock = [:SWAP_COLOR] + #always add current hairstyle as first option (in case the player just wants to swap the color) + stock << get_hair_by_id(currentHair) if $Trainer.hair + outfits_list.each { |outfit_id| + next if outfit_id == currentHair + outfit = get_hair_by_id(outfit_id) + stock << outfit if outfit + } + genericOutfitsShopMenu(stock, :HAIR, true,!free,customMessage) +end + +def switchHatsPosition() + hat1 = $Trainer.hat + hat2 = $Trainer.hat2 + hat1_color = $Trainer.hat_color + hat2_color = $Trainer.hat2_color + + $Trainer.hat = hat2 + $Trainer.hat2 = hat1 + $Trainer.hat_color = hat1_color + $Trainer.hat_color = hat2_color + + pbSEPlay("GUI naming tab swap start") +end + +SWAP_HAT_POSITIONS_CAPTION = "Switch hats position" + +#is_secondary only used for hats +def openSelectOutfitMenu(stock = [], itemType =nil, is_secondary=false) + adapter = getAdapter(itemType, stock, false, is_secondary) + view = getView(itemType) + presenter = ClothesShopPresenter.new(view, stock, adapter) + presenter.pbBuyScreen +end + +def getView(itemType) + case itemType + when :HAT + return HatShopView.new + else + return ClothesShopView.new + end +end + +def changeClothesMenu() + stock = [] + $Trainer.unlocked_clothes.each { |outfit_id| + outfit = get_clothes_by_id(outfit_id) + stock << outfit if outfit + } + openSelectOutfitMenu(stock, :CLOTHES) +end + +def changeHatMenu(is_secondary_hat = false) + stock = [] + $Trainer.unlocked_hats.each { |outfit_id| + outfit = get_hat_by_id(outfit_id) + stock << outfit if outfit + } + stock << :REMOVE_HAT + openSelectOutfitMenu(stock, :HAT, is_secondary_hat) +end + +def changeOutfit() + commands = [] + commands[cmdHat = commands.length] = _INTL("Change hat") + commands[cmdClothes = commands.length] = _INTL("Change clothes") + commands[cmdQuit = commands.length] = _INTL("Quit") + + cmd = pbMessage(_INTL("What would you like to do?"), commands, cmdQuit + 1) + loop do + if cmd == cmdClothes + changeClothesMenu() + break + elsif cmd == cmdHat + changeHatMenu() + break + else + break + end + end +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter.rb new file mode 100644 index 000000000..2956bdde5 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter.rb @@ -0,0 +1,163 @@ +class ClothesShopPresenter < PokemonMartScreen + def pbChooseBuyItem + + end + + def initialize(scene, stock, adapter = nil, versions = false) + super(scene, stock, adapter) + @use_versions = versions + end + + def putOnClothes(item,end_scene=true) + @adapter.putOnOutfit(item) if item + @scene.pbEndBuyScene if end_scene + end + + + def dyeClothes() + original_color = $Trainer.clothes_color + options = ["Shift up", "Shift down", "Reset", "Confirm", "Never Mind"] + previous_input = 0 + ret = false + while (true) + choice = pbShowCommands(nil, options, options.length, previous_input,200) + previous_input = choice + case choice + when 0 #NEXT + pbSEPlay("GUI storage pick up", 80, 100) + shiftClothesColor(10) + ret = true + when 1 #PREVIOUS + pbSEPlay("GUI storage pick up", 80, 100) + shiftClothesColor(-10) + ret = true + when 2 #Reset + pbSEPlay("GUI storage pick up", 80, 100) + $Trainer.clothes_color = 0 + ret = false + when 3 #Confirm + break + else + $Trainer.clothes_color = original_color + ret = false + break + end + @scene.updatePreviewWindow + end + return ret + end + + + # returns true if should stay in the menu + def playerClothesActionsMenu(item) + cmd_wear = "Wear" + cmd_dye = "Dye Kit" + options = [] + options << cmd_wear + options << cmd_dye if $PokemonBag.pbHasItem?(:CLOTHESDYEKIT) + options << "Cancel" + choice = pbMessage("What would you like to do?", options, -1) + + if options[choice] == cmd_wear + putOnClothes(item,false) + $Trainer.clothes_color = @adapter.get_dye_color(item.id) + return true + elsif options[choice] == cmd_dye + dyeClothes() + end + return true + end + + def confirmPutClothes(item) + putOnClothes(item) + end + + def quitMenuPrompt() + return true if !(@adapter.is_a?(HatsMartAdapter) || @adapter.is_a?(ClothesMartAdapter)) + boolean_changes_detected = @adapter.player_changed_clothes? + return true if !boolean_changes_detected + pbPlayCancelSE + cmd_confirm = "Set outfit" + cmd_discard = "Discard changes" + cmd_cancel = "Cancel" + options = [cmd_discard,cmd_confirm,cmd_cancel] + choice = pbMessage("You have unsaved changes!",options,3) + case options[choice] + when cmd_confirm + @adapter.putOnSelectedOutfit + pbPlayDecisionSE + return true + when cmd_discard + pbPlayCloseMenuSE + return true + else + return false + end + end + + def pbBuyScreen + @scene.pbStartBuyScene(@stock, @adapter) + @scene.select_specific_item(@adapter.worn_clothes) if !@adapter.isShop? + item = nil + loop do + item = @scene.pbChooseBuyItem + if !item + break if @adapter.isShop? + #quit_menu_choice = quitMenuPrompt() + #break if quit_menu_choice + break + next + end + + + if !@adapter.isShop? + if @adapter.is_a?(ClothesMartAdapter) + stay_in_menu = playerClothesActionsMenu(item) + next if stay_in_menu + return + elsif @adapter.is_a?(HatsMartAdapter) + echoln pbGet(1) + stay_in_menu = playerHatActionsMenu(item) + echoln pbGet(1) + next if stay_in_menu + return + else + if pbConfirm(_INTL("Would you like to put on the {1}?", item.name)) + confirmPutClothes(item) + return + end + next + end + next + end + itemname = @adapter.getDisplayName(item) + price = @adapter.getPrice(item) + if !price.is_a?(Integer) + pbDisplayPaused(_INTL("You already own this item!")) + if pbConfirm(_INTL("Would you like to put on the {1}?", item.name)) + @adapter.putOnOutfit(item) + end + next + end + if @adapter.getMoney < price + pbDisplayPaused(_INTL("You don't have enough money.")) + next + end + + if !pbConfirm(_INTL("Certainly. You want {1}. That will be ${2}. OK?", + itemname, price.to_s_formatted)) + next + end + if @adapter.getMoney < price + pbDisplayPaused(_INTL("You don't have enough money.")) + next + end + @adapter.setMoney(@adapter.getMoney - price) + @stock.compact! + pbDisplayPaused(_INTL("Here you are! Thank you!")) { pbSEPlay("Mart buy item") } + @adapter.addItem(item) + end + @scene.pbEndBuyScene + end + +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter_HatsMenu.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter_HatsMenu.rb new file mode 100644 index 000000000..6ef657f5e --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopPresenter_HatsMenu.rb @@ -0,0 +1,154 @@ +class ClothesShopPresenter < PokemonMartScreen + + def removeHat(item) + pbSEPlay("GUI storage put down") + @adapter.toggleEvent(item) + @scene.select_specific_item(nil,true) + end + + def wearAsHat1(item) + @adapter.set_secondary_hat(false) + putOnClothes(item) + $Trainer.set_hat_color(@adapter.get_dye_color(item.id),false) + end + def wearAsHat2(item) + @adapter.set_secondary_hat(true) + putOnClothes(item) + $Trainer.set_hat_color(@adapter.get_dye_color(item.id),true) + end + + def removeDye(item) + if pbConfirm(_INTL("Are you sure you want to remove the dye from the {1}?", item.name)) + $Trainer.set_hat_color(0,@adapter.is_secondary_hat) + end + end + + def swapHats() + echoln "hat 1: #{$Trainer.hat}" + echoln "hat 2: #{$Trainer.hat2}" + + + $Trainer.hat, $Trainer.hat2 = $Trainer.hat2, $Trainer.hat + + pbSEPlay("GUI naming tab swap start") + new_selected_hat = @adapter.is_secondary_hat ? $Trainer.hat2 : $Trainer.hat + echoln "hat 1: #{$Trainer.hat}" + echoln "hat 2: #{$Trainer.hat2}" + echoln "new selected hat: #{new_selected_hat}" + + @scene.select_specific_item(new_selected_hat,true) + @scene.updatePreviewWindow + end + + + def build_options_menu(item,cmd_confirm,cmd_remove,cmd_dye,cmd_swap,cmd_cancel) + options = [] + options << cmd_confirm + options << cmd_remove + + options << cmd_swap + options << cmd_dye if $PokemonBag.pbHasItem?(:HATSDYEKIT) + options << cmd_cancel + end + + def build_wear_options(cmd_wear_hat1,cmd_wear_hat2,cmd_replace_hat1,cmd_replace_hat2) + options = [] + primary_hat, secondary_hat = @adapter.worn_clothes, @adapter.worn_clothes2 + primary_cmds = primary_hat ? cmd_replace_hat1 : cmd_wear_hat1 + secondary_cmds = secondary_hat ? cmd_replace_hat2 : cmd_wear_hat2 + + if @adapter.is_secondary_hat + options << secondary_cmds + options << primary_cmds + else + options << primary_cmds + options << secondary_cmds + end + return options + end + + + def putOnHats() + @adapter.worn_clothes = $Trainer.hat + @adapter.worn_clothes2 = $Trainer.hat2 + + putOnHat($Trainer.hat,true,false) + putOnHat($Trainer.hat2,true,true) + + playOutfitChangeAnimation() + pbMessage(_INTL("You put on the hat(s)!\\wtnp[30]")) + end + + def dyeOptions(secondary_hat=false,item) + original_color = secondary_hat ? $Trainer.hat2_color : $Trainer.hat_color + options = ["Shift up", "Shift down", "Reset", "Confirm", "Never Mind"] + previous_input = 0 + while (true) + choice = pbShowCommands(nil, options, options.length, previous_input,200) + previous_input = choice + case choice + when 0 #NEXT + pbSEPlay("GUI storage pick up", 80, 100) + shiftHatColor(10,secondary_hat) + ret = true + when 1 #PREVIOUS + pbSEPlay("GUI storage pick up", 80, 100) + shiftHatColor(-10,secondary_hat) + ret = true + when 2 #Reset + pbSEPlay("GUI storage put down", 80, 100) + $Trainer.hat_color = 0 if !secondary_hat + $Trainer.hat2_color = 0 if secondary_hat + ret = false + when 3 #Confirm + break + else + $Trainer.hat_color = original_color if !secondary_hat + $Trainer.hat2_color = original_color if secondary_hat + ret = false + break + end + @scene.updatePreviewWindow + @scene.displayLayerIcons(item) + end + return ret + end + + def confirmPutClothes(item) + if @adapter.is_a?(HatsMartAdapter) + putOnHats() + $Trainer.hat_color = @adapter.get_dye_color($Trainer.hat) + $Trainer.hat2_color = @adapter.get_dye_color($Trainer.hat2) + else + putOnClothes(item,false) + end + end + + def playerHatActionsMenu(item) + cmd_confirm = "Confirm" + cmd_remove = "Remove hat" + cmd_cancel = "Cancel" + cmd_dye = "Dye Kit" + cmd_swap = "Swap hat positions" + + options = build_options_menu(item,cmd_confirm,cmd_remove,cmd_dye,cmd_swap,cmd_cancel) + choice = pbMessage("What would you like to do?", options, -1,nil,0) + if options[choice] == cmd_remove + removeHat(item) + return true + elsif options[choice] == cmd_confirm + confirmPutClothes(nil) + return true + elsif options[choice] == cmd_dye + dyeOptions(@adapter.is_secondary_hat,item) + return true + elsif options[choice] == cmd_swap + swapHats() + return true + elsif options[choice] == "dye" + selectHatColor + end + @scene.updatePreviewWindow + return true + end +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopView.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopView.rb new file mode 100644 index 000000000..c0fd5a22b --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/ClothesShopView.rb @@ -0,0 +1,205 @@ +class ClothesShopView < PokemonMart_Scene + + def initialize(currency_name = "Money") + @currency_name = currency_name + end + + def pbStartBuyOrSellScene(buying, stock, adapter) + super(buying, stock, adapter) + @sprites["icon"].visible = false + if @adapter.isShop? + @sprites["background"].setBitmap("Graphics/Pictures/Outfits/martScreenOutfit") + else + @sprites["background"].setBitmap("Graphics/Pictures/Outfits/changeOutfitScreen") + end + + preview_y = @adapter.isShop? ? 80 : 0 + @sprites["trainerPreview"] = TrainerClothesPreview.new(0, preview_y, true, "WALLET") + + @sprites["trainerPreview"].show() + @sprites["moneywindow"].visible = false if !@adapter.isShop? + + Kernel.pbDisplayText(@adapter.toggleText, 80, 200, 99999) if @adapter.toggleText + + end + + def select_specific_item(scroll_to_item_id,go_to_end_of_list_if_nil=false) + itemwindow = @sprites["itemwindow"] + if !scroll_to_item_id && go_to_end_of_list_if_nil + itemwindow.index=@adapter.items.length-1 + itemwindow.refresh + end + i=0 + for item in @adapter.items + next if !item.is_a?(Outfit) + if item.id == scroll_to_item_id + itemwindow.index=i + itemwindow.refresh + end + i+=1 + end + end + + def scroll_map + pbScrollMap(DIRECTION_UP, 5, 6) + pbScrollMap(DIRECTION_RIGHT, 7, 6) + @initial_direction = $game_player.direction + $game_player.turn_down + pbRefreshSceneMap + end + + def scroll_back_map + @adapter.reset_player_clothes() + pbScrollMap(DIRECTION_LEFT, 7, 6) + pbScrollMap(DIRECTION_DOWN, 5, 6) + $game_player.turn_generic(@initial_direction) + end + + def refreshStock(adapter) + @adapter = adapter + @sprites["itemwindow"].dispose if !@sprites + @sprites["itemwindow"] = Window_PokemonMart.new(@stock, BuyAdapter.new(adapter), + Graphics.width - 316 - 16, 12, 330 + 16, Graphics.height - 126) + end + + def pbRefresh + if @subscene + @subscene.pbRefresh + else + itemwindow = @sprites["itemwindow"] + item = itemwindow.item + if itemwindow.item + if itemwindow.item.is_a?(Symbol) + text = @adapter.getSpecialItemCaption(item) + else + text = @adapter.getDescription(item) + end + else + text = _INTL("Quit.") + end + @sprites["itemtextwindow"].text = text + itemwindow.refresh + end + @sprites["moneywindow"].text = _INTL("{2}:\r\n{1}", @adapter.getMoneyString, @currency_name) + end + + def updateTrainerPreview() + displayNewItem(@sprites["itemwindow"]) + end + + def displayNewItem(itemwindow) + item = itemwindow.item + if item + if item.is_a?(Symbol) + description = @adapter.getSpecialItemDescription(itemwindow.item) + else + description = @adapter.getDescription(itemwindow.item) + @adapter.updateVersion(itemwindow.item) + end + @adapter.updateTrainerPreview(itemwindow.item, @sprites["trainerPreview"]) + else + description = _INTL("Quit.") + end + @sprites["itemtextwindow"].text = description + end + + def updatePreviewWindow + itemwindow= @sprites["itemwindow"] + @adapter.updateTrainerPreview(itemwindow.item, @sprites["trainerPreview"]) + end + + def pbChooseBuyItem + itemwindow = @sprites["itemwindow"] + refreshStock(@adapter) if !itemwindow + displayNewItem(itemwindow) + @sprites["helpwindow"].visible = false + pbActivateWindow(@sprites, "itemwindow") { + pbRefresh + loop do + Graphics.update + Input.update + olditem = itemwindow.item + self.update + if itemwindow.item != olditem + displayNewItem(itemwindow) + end + if Input.trigger?(Input::AUX1) #L button - disabled because same key as speed up... + #@adapter.switchVersion(itemwindow.item, -1) + #updateTrainerPreview() + end + + if Input.trigger?(Input::AUX2) || Input.trigger?(Input::SHIFT) #R button + switchItemVersion(itemwindow) + end + if Input.trigger?(Input::SPECIAL) #R button + @adapter.toggleEvent(itemwindow.item) + updateTrainerPreview() + end + + if Input.trigger?(Input::BACK) + pbPlayCloseMenuSE + return nil + elsif Input.trigger?(Input::USE) + if itemwindow.item.is_a?(Symbol) + ret = onSpecialActionTrigger(itemwindow) + return ret if ret + elsif itemwindow.index < @stock.length + pbRefresh + return @stock[itemwindow.index] + else + return nil + end + end + end + } + end + + def onSpecialActionTrigger(itemwindow) + @adapter.doSpecialItemAction(itemwindow.item) + updateTrainerPreview() + return nil + end + def onItemClick(itemwindow) + if itemwindow.item.is_a?(Symbol) + @adapter.doSpecialItemAction(itemwindow.item) + updateTrainerPreview() + elsif itemwindow.index < @stock.length + pbRefresh + return @stock[itemwindow.index] + else + return nil + end + end + + def switchItemVersion(itemwindow) + @adapter.switchVersion(itemwindow.item, 1) + updateTrainerPreview() + end + + def update + if Input.trigger?(Input::LEFT) + pbSEPlay("GUI party switch", 80, 100) + $game_player.turn_right_90 + pbRefreshSceneMap + end + if Input.trigger?(Input::RIGHT) + pbSEPlay("GUI party switch", 80, 100) + $game_player.turn_left_90 + pbRefreshSceneMap + end + super + end + + def pbEndBuyScene + if !@sprites.empty? + @sprites["trainerPreview"].erase() + @sprites["trainerPreview"] = nil + end + pbDisposeSpriteHash(@sprites) + @viewport.dispose + Kernel.pbClearText() + # Scroll left after showing screen + scroll_back_map() + end + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairMartAdapter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairMartAdapter.rb new file mode 100644 index 000000000..70ae193fa --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairMartAdapter.rb @@ -0,0 +1,209 @@ +class HairMartAdapter < OutfitsMartAdapter + DEFAULT_NAME = "[unknown]" + DEFAULT_DESCRIPTION = "A hairstyle for trainers." + + POSSIBLE_VERSIONS = (1..9).to_a + + def initialize(stock = nil, isShop = nil) + super + + @version = getCurrentHairVersion().to_i + @worn_hair = $Trainer.hair + @worn_hat = $Trainer.hat + @worn_hat2 = $Trainer.hat2 + + @hat_visible = false + @removable = true + @previous_item= find_first_item() + end + + def find_first_item() + return @items.find { |item| item.is_a?(Outfit) } + end + + def switchVersion(item, delta = 1) + if !item.is_a?(Outfit) + item = @previous_item + end + pbSEPlay("GUI party switch", 80, 100) + newVersion = @version + delta + lastVersion = findLastHairVersion(item.id) + newVersion = lastVersion if newVersion <= 0 + newVersion = 1 if newVersion > lastVersion + @version = newVersion + end + + def player_changed_clothes?() + $Trainer.hairstyle != @worn_hair + end + + #player can't "own" hairstyles + # if you want to go back one you had before, you have to pay again + def itemOwned(item) + return false + end + + def list_regional_set_items() + return list_regional_hairstyles + end + + def list_city_exclusive_items + return list_city_exclusive_hairstyles + end + + + def toggleEvent(item) + pbSEPlay("GUI storage put down", 80, 100) + toggleHatVisibility() + end + + def toggleText() + text = "" + #text << "Color: R, \n" + text << "Toggle Hat: D\n" + + end + + def toggleHatVisibility() + @hat_visible = !@hat_visible + end + + def getPrice(item, selling = nil) + return 0 if !@isShop + trainer_hair_id = getSplitHairFilenameAndVersionFromID(@worn_hair)[1] + + + return nil if item.id == trainer_hair_id + return item.price.to_i + end + + def getDisplayPrice(item, selling = nil) + trainerStyleID = getSplitHairFilenameAndVersionFromID(@worn_hair)[1] + return "-" if item.id == trainerStyleID + super + end + + def getCurrentHairVersion() + begin + return getSplitHairFilenameAndVersionFromID($Trainer.hair)[0] + rescue + return 1 + end + end + + def getCurrentHairId(itemId) + return getFullHairId(itemId, @version) + end + + def getName(item) + echoln $Trainer.hair + return item.id + end + + def getDescription(item) + return DEFAULT_DESCRIPTION if !item.description + return item.description + end + + def getItemIcon(item) + return Settings::BACK_ITEM_ICON_PATH if !item + return getOverworldHatFilename(item.id) + end + + def updateTrainerPreview(item, previewWindow) + item = @previous_item if !item + item = @previous_item if item.is_a?(Symbol) + @previous_item = find_first_item() if !item.is_a?(Symbol) + + displayed_hat = @hat_visible ? @worn_hat : nil + displayed_hat2 = @hat_visible ? @worn_hat2 : nil + + previewWindow.hat = displayed_hat + previewWindow.hat2 = displayed_hat2 + + $Trainer.hat = displayed_hat + $Trainer.hat2 = displayed_hat2 + + itemId = getCurrentHairId(item.id) + previewWindow.hair = itemId + $Trainer.hair = itemId + pbRefreshSceneMap + previewWindow.updatePreview() + end + + def addItem(item) + itemId = getCurrentHairId(item.id) + + obtainNewHairstyle(itemId) + @worn_hair = itemId + end + + def get_current_clothes() + return $Trainer.hair + end + + def putOnOutfit(item) + itemFullId = getCurrentHairId(item.id) + putOnHair(item.id, @version) + @worn_hair = itemFullId + end + + def reset_player_clothes() + # can change hair color for free if not changing the style + if getVersionFromFullID(@worn_hair) != @version + worn_id = getSimplifiedHairIdFromFullID(@worn_hair) + if getSimplifiedHairIdFromFullID($Trainer.hair) == worn_id + @worn_hair = getFullHairId(worn_id,@version) + end + end + + $Trainer.hair = @worn_hair + $Trainer.hat = @worn_hat + $Trainer.hat2 = @worn_hat2 + + end + + def get_unlocked_items_list() + return $Trainer.unlocked_hairstyles + end + + + def getSpecialItemCaption(specialType) + case specialType + when :SWAP_COLOR + return "Swap Color" + end + return nil + end + + def getSpecialItemBaseColor(specialType) + case specialType + when :SWAP_COLOR + return MessageConfig::BLUE_TEXT_MAIN_COLOR + end + return nil + end + + def getSpecialItemShadowColor(specialType) + case specialType + when :SWAP_COLOR + return MessageConfig::BLUE_TEXT_SHADOW_COLOR + end + return nil + end + + def getSpecialItemDescription(specialType) + return "Swap to the next base hair color." + end + + def doSpecialItemAction(specialType) + switchVersion(nil,1) + end + + def currentVersionExists?(item) + hairId = getCurrentHairId(item.id) + filename = getOverworldHairFilename(hairId) + return pbResolveBitmap(filename) + end + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairShopPresenter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairShopPresenter.rb new file mode 100644 index 000000000..4dae6ce93 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HairShopPresenter.rb @@ -0,0 +1,68 @@ +class HairShopPresenter < PokemonMartScreen + def pbChooseBuyItem + + end + + def initialize(scene, stock, adapter = nil, versions=false) + super(scene,stock,adapter) + @use_versions = versions + end + + + def pbBuyScreen + @scene.pbStartBuyScene(@stock, @adapter) + item = nil + loop do + item = @scene.pbChooseBuyItem + break if !item + + if !@adapter.isShop? + if pbConfirm(_INTL("Would you like to purchase {1}?", item.name)) + @adapter.putOnOutfit(item) + @scene.pbEndBuyScene + return + end + next + + end + + itemname = @adapter.getDisplayName(item) + price = @adapter.getPrice(item) + + echoln price + if !price.is_a?(Integer) + #@adapter.switchVersion(item,1) + pbDisplayPaused(_INTL("This is your current hairstyle!")) + next + end + if @adapter.getMoney < price + pbDisplayPaused(_INTL("You don't have enough money.")) + next + end + + if !pbConfirm(_INTL("Certainly. You want {1}. That will be ${2}. OK?", + itemname, price.to_s_formatted)) + next + end + quantity = 1 + + if @adapter.getMoney < price + pbDisplayPaused(_INTL("You don't have enough money.")) + next + end + added = 0 + + @adapter.setMoney(@adapter.getMoney - price) + @stock.compact! + pbDisplayPaused(_INTL("Here you are! Thank you!")) { pbSEPlay("Mart buy item") } + @adapter.addItem(item) + #break + end + @scene.pbEndBuyScene + end + + def isWornItem?(item) + super + end + +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatShopView.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatShopView.rb new file mode 100644 index 000000000..4f18be497 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatShopView.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +class HatShopView < ClothesShopView + + def initialize(currency_name = "Money") + @currency_name = currency_name + end + + + def pbStartBuyOrSellScene(buying, stock, adapter) + super(buying, stock, adapter) + if !@adapter.isShop? + @sprites["hatLayer_selected1"] = IconSprite.new(0, 0, @viewport) + @sprites["hatLayer_selected2"] = IconSprite.new(0, 0, @viewport) + + @sprites["hatLayer_selected1"].setBitmap("Graphics/Pictures/Outfits/hatLayer_selected1") + @sprites["hatLayer_selected2"].setBitmap("Graphics/Pictures/Outfits/hatLayer_selected2") + + updateSelectedLayerGraphicsVisibility + + @sprites["wornHat_layer1"] = IconSprite.new(25, 200, @viewport) + @sprites["wornHat_layer2"] = IconSprite.new(95, 200, @viewport) + + displayLayerIcons + end + end + + def switchItemVersion(itemwindow) + @adapter.switchVersion(itemwindow.item, 1) + new_selected_hat = @adapter.is_secondary_hat ? $Trainer.hat2 : $Trainer.hat + select_specific_item(new_selected_hat,true) + updateTrainerPreview() + end + + def onSpecialActionTrigger(itemwindow) + #@adapter.doSpecialItemAction(itemwindow.item) + #updateTrainerPreview() + return @stock[itemwindow.index] + end + + def handleHatlessLayerIcons(selected_item) + other_hat = @adapter.is_secondary_hat ? $Trainer.hat : $Trainer.hat2 + if !selected_item.is_a?(Hat) + if @adapter.is_secondary_hat + @sprites["wornHat_layer2"].bitmap=nil + else + @sprites["wornHat_layer1"].bitmap=nil + end + end + if !other_hat.is_a?(Hat) + if @adapter.is_secondary_hat + @sprites["wornHat_layer1"].bitmap=nil + else + @sprites["wornHat_layer2"].bitmap=nil + end + end + + end + def displayLayerIcons(selected_item=nil) + handleHatlessLayerIcons(selected_item) + + hat1Filename = getOverworldHatFilename($Trainer.hat) + hat2Filename = getOverworldHatFilename($Trainer.hat2) + + + hat_color_shift = $Trainer.dyed_hats[$Trainer.hat] + hat2_color_shift = $Trainer.dyed_hats[$Trainer.hat2] + + hatBitmapWrapper = AnimatedBitmap.new(hat1Filename, hat_color_shift) if pbResolveBitmap(hat1Filename) + hat2BitmapWrapper = AnimatedBitmap.new(hat2Filename, hat2_color_shift) if pbResolveBitmap(hat2Filename) + + @sprites["wornHat_layer1"].bitmap = hatBitmapWrapper.bitmap if hatBitmapWrapper + @sprites["wornHat_layer2"].bitmap = hat2BitmapWrapper.bitmap if hat2BitmapWrapper + + frame_width=80 + frame_height=80 + + @sprites["wornHat_layer1"].src_rect.set(0, 0, frame_width, frame_height) if hatBitmapWrapper + @sprites["wornHat_layer2"].src_rect.set(0, 0, frame_width, frame_height) if hat2BitmapWrapper + end + + + def updateSelectedLayerGraphicsVisibility() + @sprites["hatLayer_selected1"].visible = !@adapter.is_secondary_hat + @sprites["hatLayer_selected2"].visible = @adapter.is_secondary_hat + end + + + def displayNewItem(itemwindow) + item = itemwindow.item + if item + if item.is_a?(Symbol) + description = @adapter.getSpecialItemDescription(itemwindow.item) + else + description = @adapter.getDescription(itemwindow.item) + end + @adapter.updateTrainerPreview(itemwindow.item, @sprites["trainerPreview"]) + displayLayerIcons(item) + else + description = _INTL("Quit.") + end + @sprites["itemtextwindow"].text = description + end + + def updateTrainerPreview() + super + updateSelectedLayerGraphicsVisibility + end + +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatsMartAdapter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatsMartAdapter.rb new file mode 100644 index 000000000..30b3e249f --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/clothesShop/HatsMartAdapter.rb @@ -0,0 +1,230 @@ +class HatsMartAdapter < OutfitsMartAdapter + attr_accessor :worn_clothes + attr_accessor :worn_clothes2 + + DEFAULT_NAME = "[unknown]" + DEFAULT_DESCRIPTION = "A headgear that trainers can wear." + + def initialize(stock = nil, isShop = nil, isSecondaryHat = false) + super(stock,isShop,isSecondaryHat) + @worn_clothes = $Trainer.hat + @worn_clothes2 = $Trainer.hat2 + @second_hat_visible = true + end + + #Used in shops only + def toggleSecondHat() + @second_hat_visible = !@second_hat_visible + $Trainer.hat2 = @second_hat_visible ? @worn_clothes2 : nil + end + + def toggleEvent(item) + if isShop? + toggleSecondHat + else + $Trainer.set_hat(nil,@is_secondary_hat) + @worn_clothes = nil + end + end + + def list_regional_set_items() + return list_regional_hats + end + + def list_city_exclusive_items + return list_city_exclusive_hats + end + + def set_secondary_hat(value) + @is_secondary_hat = value + end + + def is_wearing_clothes(outfit_id) + return outfit_id == @worn_clothes || outfit_id == @worn_clothes2 + end + + def toggleText() + return + # return if @isShop + # toggleKey = "D"#getMappedKeyFor(Input::SPECIAL) + # return "Remove hat: #{toggleKey}" + end + + def switchVersion(item,delta=1) + pbSEPlay("GUI storage put down", 80, 100) + return toggleSecondHat if isShop? + @is_secondary_hat = !@is_secondary_hat + end + + def getName(item) + return item.id + end + + def getDescription(item) + return DEFAULT_DESCRIPTION if !item.description + return item.description + end + + def getItemIcon(item) + return Settings::BACK_ITEM_ICON_PATH if !item + return getOverworldHatFilename(item.id) + end + + def updateTrainerPreview(item, previewWindow) + if item.is_a?(Outfit) + hat1 = @is_secondary_hat ? get_hat_by_id($Trainer.hat) : item + hat2 = @is_secondary_hat ? item : get_hat_by_id($Trainer.hat2) + + previewWindow.set_hat(hat1.id,false) if hat1 + previewWindow.set_hat(hat2.id,true) if hat2 + previewWindow.set_hat(nil,true) if !@second_hat_visible #for toggling in shops + + hat1_color=0 + hat2_color=0 + hat1_color = $Trainer.dyed_hats[hat1.id] if hat1 && $Trainer.dyed_hats.include?(hat1.id) + hat2_color = $Trainer.dyed_hats[hat2.id] if hat2 && $Trainer.dyed_hats.include?(hat2.id) + previewWindow.hat_color = hat1_color + previewWindow.hat2_color = hat2_color + + $Trainer.hat = hat1&.id + $Trainer.hat2 = hat2&.id + $Trainer.hat_color = hat1_color + $Trainer.hat2_color = hat2_color + + else + $Trainer.set_hat(nil,@is_secondary_hat) + previewWindow.set_hat(nil,@is_secondary_hat) + end + + + pbRefreshSceneMap + previewWindow.updatePreview() + end + + def get_dye_color(item_id) + return if !item_id + return 0 if isShop? + $Trainer.dyed_hats= {} if ! $Trainer.dyed_hats + if $Trainer.dyed_hats.include?(item_id) + return $Trainer.dyed_hats[item_id] + end + return 0 + end + + + def set_dye_color(item,previewWindow,is_secondary_hat=false) + return if !item + if !isShop? + + else + $Trainer.set_hat_color(0,is_secondary_hat) + previewWindow.hat_color=0 + end + end + + # def set_dye_color(item,previewWindow,is_secondary_hat=false) + # return if !item + # if !isShop? + # $Trainer.dyed_hats= {} if !$Trainer.dyed_hats + # + # echoln item.id + # echoln $Trainer.dyed_hats.include?(item.id) + # echoln $Trainer.dyed_hats[item.id] + # + # if $Trainer.dyed_hats.include?(item.id) + # dye_color = $Trainer.dyed_hats[item.id] + # $Trainer.set_hat_color(dye_color,is_secondary_hat) + # previewWindow.hat_color = dye_color + # else + # $Trainer.set_hat_color(0,is_secondary_hat) + # previewWindow.hat_color=0 + # end + # #echoln $Trainer.dyed_hats + # else + # $Trainer.set_hat_color(0,is_secondary_hat) + # previewWindow.hat_color=0 + # end + # end + + + def addItem(item) + return unless item.is_a?(Outfit) + changed_clothes = obtainHat(item.id,@is_secondary_hat) + if changed_clothes + @worn_clothes = item.id + end + end + + def get_current_clothes() + return $Trainer.hat(@is_secondary_hat) + end + + def player_changed_clothes?() + echoln("Trainer hat: #{$Trainer.hat}, Worn hat: #{@worn_clothes}") + echoln("Trainer hat2: #{$Trainer.hat2}, Worn hat2: #{@worn_clothes2}") + $Trainer.hat != @worn_clothes || $Trainer.hat2 != @worn_clothes2 + end + + def putOnSelectedOutfit() + + putOnHat($Trainer.hat,true,false) if $Trainer.hat + putOnHat($Trainer.hat2,true,true) if $Trainer.hat2 + + @worn_clothes = $Trainer.hat + @worn_clothes2 = $Trainer.hat2 + + playOutfitChangeAnimation() + pbMessage(_INTL("You put on the hat(s)!\\wtnp[30]")) + end + + def putOnOutfit(item) + return unless item.is_a?(Outfit) + putOnHat(item.id,false,@is_secondary_hat) + @worn_clothes = item.id + end + + def reset_player_clothes() + $Trainer.set_hat(@worn_clothes,false) + $Trainer.set_hat(@worn_clothes2,true) + + $Trainer.set_hat_color($Trainer.dyed_hats[@worn_clothes],false) if $Trainer.dyed_hats && $Trainer.dyed_hats[@worn_clothes] + $Trainer.set_hat_color($Trainer.dyed_hats[@worn_clothes2],true) if $Trainer.dyed_hats && $Trainer.dyed_hats[@worn_clothes2] + end + + def get_unlocked_items_list() + return $Trainer.unlocked_hats + end + + def getSpecialItemCaption(specialType) + case specialType + when :REMOVE_HAT + return "Remove hat" + end + return nil + end + + def getSpecialItemBaseColor(specialType) + case specialType + when :REMOVE_HAT + return MessageConfig::BLUE_TEXT_MAIN_COLOR + end + return nil + end + + def getSpecialItemShadowColor(specialType) + case specialType + when :REMOVE_HAT + return MessageConfig::BLUE_TEXT_SHADOW_COLOR + end + return nil + end + + def getSpecialItemDescription(specialType) + hair_situation = !$Trainer.hair || getSimplifiedHairIdFromFullID($Trainer.hair) == HAIR_BALD ? "bald head" : "fabulous hair" + return "Go without a hat and show off your #{hair_situation}!" + end + + def doSpecialItemAction(specialType,item=nil) + toggleEvent(item) + end +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairStyleSelectionMenuView.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairStyleSelectionMenuView.rb new file mode 100644 index 000000000..088aef00d --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairStyleSelectionMenuView.rb @@ -0,0 +1,160 @@ +class HairStyleSelectionMenuView + attr_accessor :name_sprite + attr_accessor :viewport + attr_accessor :sprites + attr_accessor :textValues + + + OPTIONS_START_Y = 66 + CURSOR_Y_MARGIN = 50 + CURSOR_X_MARGIN = 76 + + CHECKMARK_Y_MARGIN = 20 + CHECKMARK_WIDTH = 50 + + OPTIONS_LABEL_X = 50 + + + OPTIONS_LABEL_WIDTH = 100 + + OPTIONS_VALUE_X = 194 + SELECTOR_X = 120 + SELECTOR_STAGGER_OFFSET=26 + + + ARROW_LEFT_X_POSITION = 75 + ARROW_RIGHT_X_POSITION = 275 + ARROWS_Y_OFFSET = 10#20 + + CONFIRM_X = 296 + CONFIRM_Y= 322 + + STAGGER_OFFSET_1 = 26 + STAGGER_OFFSET_2 = 50 + + + + def initialize + @presenter = HairstyleSelectionMenuPresenter.new(self) + @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height) + @sprites = {} + @textValues={} + @max_index=5 + end + + def init_graphics() + @sprites["bg"] = IconSprite.new(@viewport) + #@sprites["bg"].setBitmap("Graphics/Pictures/trainer_application_form") + @sprites["bg"].setBitmap("") + + + @sprites["select"] = IconSprite.new(@viewport) + @sprites["select"].setBitmap("Graphics/Pictures/cc_selection_box") + @sprites["select"].x = get_cursor_x_position(0)#OPTIONS_LABEL_X + OPTIONS_LABEL_WIDTH + CURSOR_X_MARGIN + @sprites["select"].y = OPTIONS_START_Y + @sprites["select"].visible = true + + @sprites["leftarrow"] = AnimatedSprite.new("Graphics/Pictures/leftarrow", 8, 40, 28, 2, @viewport) + @sprites["leftarrow"].x = ARROW_LEFT_X_POSITION + @sprites["leftarrow"].y = 0 + @sprites["leftarrow"].visible = false + @sprites["leftarrow"].play + + + @sprites["rightarrow"] = AnimatedSprite.new("Graphics/Pictures/rightarrow", 8, 40, 28, 2, @viewport) + @sprites["rightarrow"].x = ARROW_RIGHT_X_POSITION + @sprites["rightarrow"].y = 0 + @sprites["rightarrow"].visible = false + @sprites["rightarrow"].play + end + + def setMaxIndex(maxIndex) + @max_index=maxIndex + end + + def init_labels() + Kernel.pbDisplayText("Confirm", (CONFIRM_X+CURSOR_X_MARGIN), CONFIRM_Y) + end + + + + def start + init_graphics() + init_labels() + @presenter.main() + end + + def get_cursor_y_position(index) + return CONFIRM_Y if index == @max_index + return index * CURSOR_Y_MARGIN + OPTIONS_START_Y + end + + def get_cursor_x_position(index) + return CONFIRM_X if index == @max_index + return SELECTOR_X + getTextBoxStaggerOffset(index) + end + + def get_value_x_position(index) + return (OPTIONS_VALUE_X + getTextBoxStaggerOffset(index)) + end + + def getTextBoxStaggerOffset(index) + case index + when 1 + return STAGGER_OFFSET_1 + when 2 + return STAGGER_OFFSET_2 + when 3 + return STAGGER_OFFSET_1 + end + return 0 + end + + + + + def showSideArrows(y_index) + y_position = get_cursor_y_position(y_index) + + @sprites["rightarrow"].y=y_position+ARROWS_Y_OFFSET + @sprites["leftarrow"].y=y_position+ARROWS_Y_OFFSET + + @sprites["leftarrow"].x=getTextBoxStaggerOffset(y_index)+ARROW_LEFT_X_POSITION + @sprites["rightarrow"].x= getTextBoxStaggerOffset(y_index)+ARROW_RIGHT_X_POSITION + + @sprites["rightarrow"].visible=true + @sprites["leftarrow"].visible=true + end + + def hideSideArrows() + @sprites["rightarrow"].visible=false + @sprites["leftarrow"].visible=false + end + + def displayText(spriteId,text,y_index) + @textValues[spriteId].dispose if @textValues[spriteId] + yposition = get_cursor_y_position(y_index) + xposition = get_value_x_position(y_index) + + baseColor= baseColor ? baseColor : Color.new(72,72,72) + shadowColor= shadowColor ? shadowColor : Color.new(160,160,160) + @textValues[spriteId] = BitmapSprite.new(Graphics.width,Graphics.height,@viewport) + text1=_INTL(text) + textPosition=[ + [text1,xposition,yposition,2,baseColor,shadowColor], + ] + pbSetSystemFont(@textValues[spriteId].bitmap) + pbDrawTextPositions(@textValues[spriteId].bitmap,textPosition) + + end + + + def updateGraphics() + Graphics.update + Input.update + if @sprites + @sprites["rightarrow"].update + @sprites["leftarrow"].update + end + end +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairstyleSelectionMenuPresenter.rb b/Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairstyleSelectionMenuPresenter.rb new file mode 100644 index 000000000..47b2e6e3a --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/UI/hairMenu/HairstyleSelectionMenuPresenter.rb @@ -0,0 +1,187 @@ +class HairstyleSelectionMenuPresenter + attr_accessor :options + attr_reader :current_index + + OPTION_STYLE = 'Hairstyle' + OPTION_BASE_COLOR = "Base color" + OPTION_DYE = "Dye" + + HAIR_COLOR_NAMES = ["Blonde", "Light Brown", "Dark Brown", "Black"] + HAIR_COLOR_IDS = [1, 2, 3, 4] + + #ids for displayed text sprites + STYLE_TEXT_ID = "style" + BASECOLOR_TEXT_ID = "baseCplor" + DYE_TEXT_ID = "dye" + + def initialize(view) + @view = view + @hairstyle_full_id = $Trainer.hair + + hairstyle_split = getSplitHairFilenameAndVersionFromID(@hairstyle_full_id) + @hairstyle = hairstyle_split[0] if hairstyle_split[0] + @hair_version = hairstyle_split[1] if hairstyle_split[1] + @hairColor = $Trainer.hair_color + + @available_styles= $Trainer.unlocked_hairstyles + @selected_hairstyle_index = 0 + + echoln @available_styles + + @options = [OPTION_STYLE, OPTION_BASE_COLOR, OPTION_DYE] + + @trainerPreview = TrainerClothesPreview.new(300, 80, false) + @trainerPreview.show() + @closed = false + @current_index = 0 + @view.setMaxIndex(@options.length - 1) + end + + def main() + pbSEPlay("GUI naming tab swap start", 80, 100) + @current_index = 0 + loop do + @view.updateGraphics() + if Input.trigger?(Input::DOWN) + @current_index = move_menu_vertical(1) + elsif Input.trigger?(Input::UP) + @current_index = move_menu_vertical(-1) + elsif Input.trigger?(Input::RIGHT) + move_menu_horizontal(@current_index, 1) + elsif Input.trigger?(Input::LEFT) + move_menu_horizontal(@current_index, -1) + elsif Input.trigger?(Input::ACTION) || Input.trigger?(Input::USE) + action_button_pressed(@current_index) + end + break if @closed + end + end + + def updateTrainerPreview + @trainerPreview.resetOutfits + @trainerPreview.updatePreview + end + + def action_button_pressed(current_index) + pbSEPlay("GUI save choice", 80, 100) + @current_index = @options.length - 1 + update_cursor(@current_index) + end + + def getDefaultName() + return DEFAULT_NAMES[@gender] + end + + + def applyAllSelectedValues + $Trainer.hair = getFullHairId(@hairstyle,@hair_version) + $Trainer.hair_color = @hairColor + end + + def getOptionIndex(option_name) + i = 0 + for option in @options + return i if option == option_name + i += 1 + end + return -1 + end + + #VERTICAL NAVIGATION + + def move_menu_vertical(offset) + pbSEPlay("GUI sel decision", 80, 100) + @current_index += offset + @current_index = 0 if @current_index > @options.length - 1 + @current_index = @options.length - 1 if @current_index <= -1 + + update_cursor(@current_index) + return @current_index + end + + def update_cursor(index) + @view.sprites["select"].y = @view.get_cursor_y_position(index) + @view.sprites["select"].x = @view.get_cursor_x_position(index) + + set_custom_cursor(index) + end + + def close_menu + @trainerPreview.erase() + Kernel.pbClearNumber() + Kernel.pbClearText() + pbDisposeSpriteHash(@view.sprites) + pbDisposeSpriteHash(@view.textValues) + @closed = true + end + + def set_custom_cursor(index) + # selected_option = @options[index] + # case selected_option + # when OPTION_GENDER + # @view.showSideArrows(index) + # when OPTION_AGE + # @view.showSideArrows(index) + # when OPTION_HAIR + # @view.showSideArrows(index) + # when OPTION_SKIN + # @view.showSideArrows(index) + # else + # @view.hideSideArrows + # end + end + + #HORIZONTAL NAVIGATION + def move_menu_horizontal(current_index, incr) + pbSEPlay("GUI sel cursor", 80, 100) + selected_option = @options[current_index] + case selected_option + when OPTION_STYLE then + setHairstyle(@selected_hairstyle_index,incr) + end + + # case selected_option + # when OPTION_GENDER then + # setGender(current_index, incr) + # when OPTION_HAIR then + # setHairColor(current_index, incr) + # when OPTION_SKIN then + # setSkinColor(current_index, incr) + # when OPTION_AGE then + # setAge(current_index, incr) + # end + updateTrainerPreview() + end + + + + def setHairstyle(current_index, incr) + @selected_hairstyle_index += incr + @selected_hairstyle_index = 0 if @selected_hairstyle_index > @available_styles.length + @selected_hairstyle_index = @available_styles.length-1 if @selected_hairstyle_index < 0 + + @hairstyle = @available_styles[@selected_hairstyle_index] + + applyHair() + echoln @hairstyle + echoln "hairstyle: #{@hairstyle}, full list: #{@available_styles}, index: #{current_index}" + + @view.displayText(STYLE_TEXT_ID, @hairstyle, @selected_hairstyle_index) + end + + def setBaseColor(current_index, incr) + max_id = HAIR_COLOR_IDS.length - 1 + @hairColor += incr + @hairColor = 0 if @hairColor > max_id + @hairColor = max_id if @hairColor <= -1 + applyHair() + @view.displayText(BASECOLOR_TEXT_ID, HAIR_COLOR_NAMES[@hairColor], current_index) + end + + def applyHair() + hairstyle = @hairstyle + hair_version =@hair_version + hairId = getFullHairId(hairstyle,hair_version) + $Trainer.hair = hairId + end +end diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitFilenameUtils.rb b/Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitFilenameUtils.rb new file mode 100644 index 000000000..2bf2162ea --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitFilenameUtils.rb @@ -0,0 +1,126 @@ +#Naked sprites +BASE_FOLDER = "base" +BASE_OVERWORLD_FOLDER = "overworld" +BASE_TRAINER_FOLDER = "trainer" + +def getBaseOverworldSpriteFilename(action = "walk", skinTone = "default") + base_path = Settings::PLAYER_GRAPHICS_FOLDER + BASE_FOLDER + "/" + BASE_OVERWORLD_FOLDER + dynamic_path = _INTL("/{1}/{2}_{1}", skinTone, action) + full_path = base_path + dynamic_path + return full_path if pbResolveBitmap(full_path) + return getBaseOverworldSpriteFilename(action) if skinTone != "default" #try again with default skintone + return nil +end + +def getBaseTrainerSpriteFilename(skinTone = "default") + base_path = Settings::PLAYER_GRAPHICS_FOLDER + BASE_FOLDER + "/" + BASE_TRAINER_FOLDER + dynamic_path = _INTL("/{1}_{2}", BASE_TRAINER_FOLDER, skinTone) + full_path = base_path + dynamic_path + return full_path if pbResolveBitmap(full_path) + return getBaseTrainerSpriteFilename() #default skintone +end + +### OUTFIT # + +def get_clothes_sets_list_path() + return Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_CLOTHES_FOLDER +end + +def getOverworldOutfitFilename(outfit_id, action="walk") + base_path = Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_CLOTHES_FOLDER + dynamic_path = _INTL("/{1}/", outfit_id) + filename = _INTL(Settings::PLAYER_CLOTHES_FOLDER + "_{1}_{2}", action, outfit_id) + full_path = base_path + dynamic_path + filename + #echoln full_path + return full_path +end + +def getTrainerSpriteOutfitFilename(outfit_id) + return getOverworldOutfitFilename(outfit_id, BASE_TRAINER_FOLDER) +end + +#### HAIR + +def get_hair_sets_list_path() + return Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_HAIR_FOLDER +end + + +def getSimplifiedHairIdFromFullID(full_id) + split_id = getSplitHairFilenameAndVersionFromID(full_id) + return split_id[1] if split_id.length > 1 + return "" +end + +def getVersionFromFullID(full_id) + split_id = getSplitHairFilenameAndVersionFromID(full_id) + return split_id[0] +end + +# Input: 1_red +# Output: ["1","red"] +def getSplitHairFilenameAndVersionFromID(hairstyle_id) + return "" if !hairstyle_id + hairstyle_id= hairstyle_id.to_s + return hairstyle_id.split("_") +end + +def getFullHairId(hairstyle,version) + return _INTL("{1}_{2}",version,hairstyle) + +end + +def getOverworldHairFilename(hairstyle_id) + hairstyle_split = getSplitHairFilenameAndVersionFromID(hairstyle_id) + name= hairstyle_split[-1] + version= hairstyle_split[-2] + + base_path = Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_HAIR_FOLDER + dynamic_path = _INTL("/{1}/", name) + filename = _INTL(Settings::PLAYER_HAIR_FOLDER + "_{1}_{2}",version, name) + full_path = base_path + dynamic_path + filename + return full_path +end + +def getTrainerSpriteHairFilename(hairstyle_id) + return "" if !hairstyle_id + hairstyle_id= hairstyle_id.to_s + hairstyle_split= hairstyle_id.split("_") + name= hairstyle_split[-1] + version= hairstyle_split[-2] + + + base_path = Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_HAIR_FOLDER + dynamic_path = _INTL("/{1}/", name) + filename = _INTL(Settings::PLAYER_HAIR_FOLDER + "_trainer_{1}_{2}",version, name) + full_path = base_path + dynamic_path + filename + return full_path +end + +#### HATS +# +def get_hats_sets_list_path() + return Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_HAT_FOLDER +end + +def getOverworldHatFilename(hat_id) + base_path = Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_HAT_FOLDER + dynamic_path = _INTL("/{1}/", hat_id) + filename = _INTL(Settings::PLAYER_HAT_FOLDER + "_{1}", hat_id) + full_path = base_path + dynamic_path + filename + return full_path +end + +def getTrainerSpriteHatFilename(hat_id) + base_path = Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_HAT_FOLDER + dynamic_path = _INTL("/{1}/", hat_id) + filename = _INTL(Settings::PLAYER_HAT_FOLDER + "_trainer_{1}", hat_id) + full_path = base_path + dynamic_path + filename + return full_path +end + +def getTrainerSpriteBallFilename(pokeball) + base_path = Settings::PLAYER_GRAPHICS_FOLDER + Settings::PLAYER_BALL_FOLDER + + return base_path + "/" + pokeball.to_s +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitsGameplayUtils.rb b/Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitsGameplayUtils.rb new file mode 100644 index 000000000..fe932d08b --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/utils/OutfitsGameplayUtils.rb @@ -0,0 +1,412 @@ +def obtainNewHat(outfit_id) + return obtainHat(outfit_id) +end + +def obtainNewClothes(outfit_id) + return obtainClothes(outfit_id) +end + +def obtainHat(outfit_id,secondary=false) + echoln "obtained new hat: " + outfit_id + outfit = get_hat_by_id(outfit_id) + if !outfit + pbMessage(_INTL("The hat #{outfit_id} is invalid.")) + return + end + $Trainer.unlocked_hats << outfit_id if !$Trainer.unlocked_hats.include?(outfit_id) + obtainOutfitMessage(outfit) + if pbConfirmMessage("Would you like to put it on right now?") + putOnHat(outfit_id, false, false) if !secondary + putOnHat(outfit_id, false, true) if secondary + return true + end + return false +end + +def obtainClothes(outfit_id) + echoln "obtained new clothes: " + outfit_id + outfit = get_clothes_by_id(outfit_id) + if !outfit + pbMessage(_INTL("The clothes #{outfit_id} are invalid.")) + return + end + return if !outfit + $Trainer.unlocked_clothes << outfit_id if !$Trainer.unlocked_clothes.include?(outfit_id) + obtainOutfitMessage(outfit) + if pbConfirmMessage("Would you like to put it on right now?") + putOnClothes(outfit_id) + return true + end + return false +end + +def obtainNewHairstyle(full_outfit_id) + split_outfit_id = getSplitHairFilenameAndVersionFromID(full_outfit_id) + hairstyle_id = split_outfit_id[1] + hairstyle = get_hair_by_id(hairstyle_id) + musical_effect = "Key item get" + pbMessage(_INTL("\\me[{1}]Your hairstyle was changed to \\c[1]{2}\\c[0] hairstyle!\\wtnp[30]", musical_effect, hairstyle.name)) + return true +end + +def putOnClothes(outfit_id, silent = false) + $Trainer.dyed_clothes= {} if ! $Trainer.dyed_clothes + $Trainer.last_worn_outfit = $Trainer.clothes + outfit = get_clothes_by_id(outfit_id) + $Trainer.clothes = outfit_id + + dye_color = $Trainer.dyed_clothes[outfit_id] + if dye_color + $Trainer.clothes_color = dye_color + else + $Trainer.clothes_color = nil + end + + $game_map.update + refreshPlayerOutfit() + putOnOutfitMessage(outfit) if !silent +end + +def putOnHat(outfit_id, silent = false, is_secondary=false) + $Trainer.dyed_hats= {} if ! $Trainer.dyed_hats + $Trainer.set_last_worn_hat($Trainer.hat,is_secondary) + outfit = get_hat_by_id(outfit_id) + + $Trainer.set_hat(outfit_id,is_secondary) + + dye_color = $Trainer.dyed_hats[outfit_id] + if dye_color + $Trainer.hat_color = dye_color if !is_secondary + $Trainer.hat2_color = dye_color if is_secondary + else + $Trainer.hat_color = nil if !is_secondary + $Trainer.hat2_color = nil if is_secondary + end + + $game_map.refreshPlayerOutfit() + putOnOutfitMessage(outfit) if !silent +end + + +def putOnHairFullId(full_outfit_id) + outfit_id = getSplitHairFilenameAndVersionFromID(full_outfit_id)[1] + outfit = get_hair_by_id(outfit_id) + $Trainer.hair = full_outfit_id + $game_map.update + refreshPlayerOutfit() + putOnOutfitMessage(outfit) +end + +def putOnHair(outfit_id, version) + full_id = getFullHairId(outfit_id, version) + putOnHairFullId(full_id) + #outfit = get_hair_by_id(outfit_id) + #$Trainer.hair = + #putOnOutfitMessage(outfit) +end + +def showOutfitPicture(outfit) + begin + outfitPath = outfit.trainer_sprite_path() + + viewport = Viewport.new(Graphics.width / 4, 0, Graphics.width / 2, Graphics.height) + bg_sprite = Sprite.new(viewport) + outfit_sprite = Sprite.new(viewport) + outfit_bitmap = AnimatedBitmap.new(outfitPath) if pbResolveBitmap(outfitPath) + bg_bitmap = AnimatedBitmap.new("Graphics/Pictures/Outfits/obtain_bg") + + outfit_sprite.bitmap = outfit_bitmap.bitmap + bg_sprite.bitmap = bg_bitmap.bitmap + + # bitmap = AnimatedBitmap.new("Graphics/Pictures/Outfits/obtain_bg") + outfit_sprite.x = -50 + outfit_sprite.y = 50 + outfit_sprite.y -= 120 if outfit.type == :CLOTHES + + # outfit_sprite.y = Graphics.height/2 + outfit_sprite.zoom_x = 2 + outfit_sprite.zoom_y = 2 + + bg_sprite.x = 0 + + viewport.z = 99999 + # bg_sprite.y = Graphics.height/2 + + return viewport + rescue + #ignore + end +end + +def obtainOutfitMessage(outfit) + pictureViewport = showOutfitPicture(outfit) + musical_effect = "Key item get" + pbMessage(_INTL("\\me[{1}]You obtained a \\c[1]{2}\\c[0]!\\wtnp[30]", musical_effect, outfit.name)) + pictureViewport.dispose if pictureViewport +end + +def putOnOutfitMessage(outfit) + playOutfitChangeAnimation() + outfitName = outfit.name == "" ? outfit.id : outfit.name + pbMessage(_INTL("You put on the \\c[1]{1}\\c[0]!\\wtnp[30]", outfitName)) +end + +def refreshPlayerOutfit() + return if !$scene.spritesetGlobal + $scene.spritesetGlobal.playersprite.refreshOutfit() +end + +def findLastHairVersion(hairId) + possible_versions = (1..9).to_a + last_version = 0 + possible_versions.each { |version| + hair_id = getFullHairId(hairId, version) + echoln hair_id + echoln pbResolveBitmap(getOverworldHairFilename(hair_id)) + if pbResolveBitmap(getOverworldHairFilename(hair_id)) + last_version = version + else + return last_version + end + } + return last_version +end + +def isWearingClothes(outfitId) + return $Trainer.clothes == outfitId +end + +def isWearingHat(outfitId) + return $Trainer.hat == outfitId || $Trainer.hat2 == outfitId +end + +def isWearingHairstyle(outfitId, version = nil) + current_hair_split_id = getSplitHairFilenameAndVersionFromID($Trainer.hair) + current_id = current_hair_split_id.length >= 1 ? current_hair_split_id[1] : nil + current_version = current_hair_split_id[0] + if version + return outfitId == current_id && version == current_version + end + return outfitId == current_id +end + +#Some game switches need to be on/off depending on the outfit that the player is wearing, +# this is called every time you change outfit to make sure that they're always updated correctly +def updateOutfitSwitches(refresh_map = true) + $game_switches[WEARING_ROCKET_OUTFIT] = isWearingTeamRocketOutfit() + #$game_map.update + + #$scene.reset_map(true) if refresh_map + #$scene.reset_map(false) +end + +def getDefaultClothes() + gender = pbGet(VAR_TRAINER_GENDER) + if gender == GENDER_MALE + return DEFAULT_OUTFIT_MALE + end + return DEFAULT_OUTFIT_FEMALE +end + +def hasClothes?(outfit_id) + return $Trainer.unlocked_clothes.include?(outfit_id) +end + +def hasHat?(outfit_id) + return $Trainer.unlocked_hats.include?(outfit_id) +end + +def getOutfitForPokemon(pokemonSpecies) + possible_clothes = [] + possible_hats = [] + + body_pokemon_id = get_body_species_from_symbol(pokemonSpecies).to_s.downcase + head_pokemon_id = get_head_species_from_symbol(pokemonSpecies).to_s.downcase + body_pokemon_tag = "pokemon-#{body_pokemon_id}" + head_pokemon_tag = "pokemon-#{head_pokemon_id}" + + possible_hats += search_hats([body_pokemon_tag]) + possible_hats += search_hats([head_pokemon_tag]) + possible_clothes += search_clothes([body_pokemon_tag]) + possible_clothes += search_clothes([head_pokemon_tag]) + + if isFusion(getDexNumberForSpecies(pokemonSpecies)) + possible_hats += search_hats(["pokemon-fused"], [], false) + possible_clothes += search_clothes(["pokemon-fused"], false) + end + + possible_hats = filter_hats_only_not_owned(possible_hats) + possible_clothes = filter_clothes_only_not_owned(possible_clothes) + + if !possible_hats.empty?() && !possible_clothes.empty?() #both have values, pick one at random + return [[possible_hats.sample, :HAT], [possible_clothes.sample, :CLOTHES]].sample + elsif !possible_hats.empty? + return [possible_hats.sample, :HAT] + elsif !possible_clothes.empty? + return [possible_clothes.sample, :CLOTHES] + end + return [] +end + +def hatUnlocked?(hatId) + return $Trainer.unlocked_hats.include?(hatId) +end + +def export_current_outfit() + skinTone = $Trainer.skin_tone ? $Trainer.skin_tone : 0 + hat = $Trainer.hat ? $Trainer.hat : "nil" + hair_color = $Trainer.hair_color || 0 + clothes_color = $Trainer.clothes_color || 0 + hat_color = $Trainer.hat_color || 0 + exportedString = "TrainerAppearance.new(#{skinTone},\"#{hat}\",\"#{$Trainer.clothes}\",\"#{$Trainer.hair}\",#{hair_color},#{clothes_color},#{hat_color})" + Input.clipboard = exportedString +end + +def clearEventCustomAppearance(event_id) + return if !$scene.is_a?(Scene_Map) + event_sprite = $scene.spriteset.character_sprites[@event_id] + for sprite in $scene.spriteset.character_sprites + if sprite.character.id == event_id + event_sprite = sprite + end + end + return if !event_sprite + event_sprite.clearBitmapOverride +end + +def setEventAppearance(event_id, trainerAppearance) + return if !$scene.is_a?(Scene_Map) + event_sprite = $scene.spriteset.character_sprites[@event_id] + for sprite in $scene.spriteset.character_sprites + if sprite.character.id == event_id + event_sprite = sprite + end + end + return if !event_sprite + event_sprite.setSpriteToAppearance(trainerAppearance) +end + +def getPlayerAppearance() + return TrainerAppearance.new($Trainer.skin_tone,$Trainer.hat,$Trainer.clothes, $Trainer.hair, + $Trainer.hair_color, $Trainer.clothes_color, $Trainer.hat_color) +end + +def randomizePlayerOutfitUnlocked() + $Trainer.hat = $Trainer.unlocked_hats.sample + $Trainer.hat2 = $Trainer.unlocked_hats.sample + $Trainer.clothes = $Trainer.unlocked_clothes.sample + + dye_hat = rand(2)==0 + dye_hat2 = rand(2)==0 + dye_clothes = rand(2)==0 + dye_hair = rand(2)==0 + $Trainer.hat2 = nil if rand(3)==0 + + $Trainer.hat_color = dye_hat ? rand(255) : 0 + $Trainer.hat2_color = dye_hat2 ? rand(255) : 0 + + $Trainer.clothes_color = dye_clothes ? rand(255) : 0 + $Trainer.hair_color = dye_hair ? rand(255) : 0 + + hair_id = $PokemonGlobal.hairstyles_data.keys.sample + hair_color = [1,2,3,4].sample + $Trainer.hair = getFullHairId(hair_id,hair_color) + +end + +def convert_letter_to_number(letter, max_number = nil) + return 0 unless letter + base_value = (letter.ord * 31) & 0xFFFFFFFF # Use a prime multiplier to spread values + return base_value unless max_number + return base_value % max_number +end + + +def generate_appearance_from_name(name) + name_seed_length = 13 + max_dye_color=360 + + seed = name[0, name_seed_length] # Truncate if longer than 8 + seed += seed[0, name_seed_length - seed.length] while seed.length < name_seed_length # Repeat first characters if shorter + + echoln seed + + hats_list = $PokemonGlobal.hats_data.keys + clothes_list = $PokemonGlobal.clothes_data.keys + hairstyles_list = $PokemonGlobal.hairstyles_data.keys + + hat = hats_list[convert_letter_to_number(seed[0],hats_list.length)] + hat_color = convert_letter_to_number(seed[1],max_dye_color) + hat2_color = convert_letter_to_number(seed[2],max_dye_color) + hat_color = 0 if convert_letter_to_number(seed[2]) % 2 == 0 #1/2 chance of no dyed hat + + hat2 = hats_list[convert_letter_to_number(seed[10],hats_list.length)] + hat2_color = 0 if convert_letter_to_number(seed[11]) % 2 == 0 #1/2 chance of no dyed ha + hat2 = "" if convert_letter_to_number(seed[12]) % 2 == 0 #1/2 chance of no 2nd hat + + clothes = clothes_list[convert_letter_to_number(seed[3],clothes_list.length)] + clothes_color = convert_letter_to_number(seed[4],max_dye_color) + clothes_color = 0 if convert_letter_to_number(seed[5]) % 2 == 0 #1/2 chance of no dyed clothes + + hair_base = hairstyles_list[convert_letter_to_number(seed[6],hairstyles_list.length)] + hair_number = [1,2,3,4][convert_letter_to_number(seed[7],3)] + echoln "hair_number: #{hair_number}" + + hair=getFullHairId(hair_base,hair_number) + hair_color = convert_letter_to_number(seed[8],max_dye_color) + hair_color = 0 if convert_letter_to_number(seed[9]) % 2 == 0 #1/2 chance of no dyed hair + + echoln hair_color + echoln clothes_color + echoln hat_color + + skin_tone = [1,2,3,4,5,6][convert_letter_to_number(seed[10],5)] + return TrainerAppearance.new(skin_tone,hat,clothes, hair, + hair_color, clothes_color, hat_color, + hat2,hat2_color) + +end + +def get_random_appearance() + hat = $PokemonGlobal.hats_data.keys.sample + hat2 = $PokemonGlobal.hats_data.keys.sample + hat2 = nil if(rand(3)==0) + + clothes = $PokemonGlobal.clothes_data.keys.sample + hat_color = rand(2)==0 ? rand(255) : 0 + hat2_color = rand(2)==0 ? rand(255) : 0 + + clothes_color = rand(2)==0 ? rand(255) : 0 + hair_color = rand(2)==0 ? rand(255) : 0 + + hair_id = $PokemonGlobal.hairstyles_data.keys.sample + hair_color = [1,2,3,4].sample + skin_tone = [1,2,3,4,5,6].sample + hair = getFullHairId(hair_id,hair_color) + + return TrainerAppearance.new(skin_tone,hat,clothes, hair, + hair_color, clothes_color, hat_color,hat2) +end + +def randomizePlayerOutfit() + $Trainer.hat = $PokemonGlobal.hats_data.keys.sample + $Trainer.hat2 = $PokemonGlobal.hats_data.keys.sample + $Trainer.hat2 = nil if(rand(3)==0) + + $Trainer.clothes = $PokemonGlobal.clothes_data.keys.sample + $Trainer.hat_color = rand(2)==0 ? rand(255) : 0 + $Trainer.hat2_color = rand(2)==0 ? rand(255) : 0 + + $Trainer.clothes_color = rand(2)==0 ? rand(255) : 0 + $Trainer.hair_color = rand(2)==0 ? rand(255) : 0 + + hair_id = $PokemonGlobal.hairstyles_data.keys.sample + hair_color = [1,2,3,4].sample + $Trainer.skin_tone = [1,2,3,4,5,6].sample + $Trainer.hair = getFullHairId(hair_id,hair_color) + +end + +def canPutHatOnPokemon(pokemon) + return !pokemon.egg? && !pokemon.isTripleFusion? && $game_switches[SWITCH_UNLOCKED_POKEMON_HATS] +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/001_Outfit.rb b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/001_Outfit.rb new file mode 100644 index 000000000..9bc8b6e2c --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/001_Outfit.rb @@ -0,0 +1,19 @@ +class Outfit + attr_accessor :id + attr_accessor :name + attr_accessor :description + attr_accessor :tags + attr_accessor :price + + def initialize(id, name, description = '',price=0, tags = []) + @id = id + @name = name + @description = description + @tags = tags + @price = price + end + + def trainer_sprite_path() + return nil + end +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Clothes.rb b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Clothes.rb new file mode 100644 index 000000000..a0a0be896 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Clothes.rb @@ -0,0 +1,11 @@ +class Clothes < Outfit + attr_accessor :type + def initialize(id, name, description = '',price=0, tags = []) + super + @type = :CLOTHES + end + + def trainer_sprite_path() + return getTrainerSpriteOutfitFilename(self.id) + end +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hairstyle.rb b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hairstyle.rb new file mode 100644 index 000000000..446e5d101 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hairstyle.rb @@ -0,0 +1,12 @@ +class Hairstyle < Outfit + attr_accessor :type + def initialize(id, name, description = '',price=0, tags = []) + super + @type = :HAIR + end + + def trainer_sprite_path() + return getTrainerSpriteHairFilename(self.id) + end + +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hat.rb b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hat.rb new file mode 100644 index 000000000..b156b380e --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Outfits/wrappers/Hat.rb @@ -0,0 +1,11 @@ +class Hat < Outfit + attr_accessor :type + def initialize(id,name,description='',price=0,tags=[]) + super + @type = :HAT + end + + def trainer_sprite_path() + return getTrainerSpriteHatFilename(self.id) + end +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Player/PlayerAddons.rb b/Data/Scripts/998_InfiniteFusion/Player/PlayerAddons.rb new file mode 100644 index 000000000..775109d2a --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Player/PlayerAddons.rb @@ -0,0 +1,291 @@ +class Player < Trainer + attr_accessor :skin_tone + attr_accessor :clothes + attr_accessor :hat + attr_accessor :hat2 + + attr_accessor :hair + attr_accessor :hair_color + attr_accessor :hat_color + attr_accessor :hat2_color + + attr_accessor :clothes_color + attr_accessor :unlocked_clothes + attr_accessor :unlocked_hats + attr_accessor :unlocked_hairstyles + attr_accessor :unlocked_card_backgrounds + + attr_accessor :dyed_hats + attr_accessor :dyed_clothes + + attr_accessor :favorite_hat + attr_accessor :favorite_hat2 + + attr_accessor :favorite_clothes + + attr_accessor :last_worn_outfit + attr_accessor :last_worn_hat + attr_accessor :last_worn_hat2 + + attr_accessor :surfing_pokemon + + attr_accessor :card_background + attr_accessor :unlocked_card_backgrounds + + attr_accessor :seen_qmarks_sprite + + attr_accessor :beat_league + attr_accessor :new_game_plus_unlocked + + def last_worn_outfit + if !@last_worn_outfit + if pbGet(VAR_TRAINER_GENDER) == GENDER_MALE + @last_worn_outfit = DEFAULT_OUTFIT_MALE + else + @last_worn_outfit = DEFAULT_OUTFIT_FEMALE + end + end + return @last_worn_outfit + end + + def last_worn_hat(is_secondary = false) + return is_secondary ? @last_worn_hat2 : @last_worn_hat + end + + def set_last_worn_hat(value, is_secondary = false) + if is_secondary + @last_worn_hat = value + else + @last_worn_hat = value + end + end + + def last_worn_hat2 + return @last_worn_hat2 + end + + def outfit=(value) + @outfit = value + end + + def favorite_hat(is_secondary = false) + return is_secondary ? @favorite_hat2 : @favorite_hat + end + + # todo change to set_favorite_hat(value,is_secondary=false) + def set_favorite_hat(value, is_secondary = false) + if is_secondary + @favorite_hat = value + else + @favorite_hat2 = value + end + end + + def hat_color(is_secondary = false) + return is_secondary ? @hat2_color : @hat_color + end + + def hat(is_secondary = false) + return is_secondary ? @hat2 : @hat + end + + def set_hat(value, is_secondary = false) + if value.is_a?(Symbol) + value = HATS[value].id + end + if is_secondary + @hat2 = value + else + @hat = value + end + refreshPlayerOutfit() + end + + # todo : refactor to always use set_hat instead + def hat=(value) + if value.is_a?(Symbol) + value = HATS[value].id + end + @hat = value + refreshPlayerOutfit() + end + + # todo : refactor to always use set_hat instead + def hat2=(value) + if value.is_a?(Symbol) + value = HATS[value].id + end + @hat2 = value + refreshPlayerOutfit() + end + + def hair=(value) + if value.is_a?(Symbol) + value = HAIRSTYLES[value].id + end + @hair = value + refreshPlayerOutfit() + end + + def clothes=(value) + if value.is_a?(Symbol) + value = OUTFITS[value].id + end + @clothes = value + refreshPlayerOutfit() + end + + def clothes_color=(value) + @clothes_color = value + $Trainer.dyed_clothes = {} if !$Trainer.dyed_clothes + $Trainer.dyed_clothes[@clothes] = value if value + refreshPlayerOutfit() + end + + def set_hat_color(value, is_secondary = false) + if is_secondary + @hat2_color = value + else + @hat_color = value + end + $Trainer.dyed_hats = {} if !$Trainer.dyed_hats + worn_hat = is_secondary ? @hat2 : @hat + $Trainer.dyed_hats[worn_hat] = value if value + refreshPlayerOutfit() + end + + def hat_color=(value) + @hat_color = value + $Trainer.dyed_hats = {} if !$Trainer.dyed_hats + worn_hat = @hat + $Trainer.dyed_hats[worn_hat] = value if value + refreshPlayerOutfit() + end + + def hat2_color=(value) + @hat2_color = value + $Trainer.dyed_hats = {} if !$Trainer.dyed_hats + worn_hat = @hat2 + $Trainer.dyed_hats[worn_hat] = value if value + refreshPlayerOutfit() + end + + def unlock_clothes(outfitID, silent = false) + update_global_clothes_list() + outfit = $PokemonGlobal.clothes_data[outfitID] + @unlocked_clothes = [] if !@unlocked_clothes + @unlocked_clothes << outfitID if !@unlocked_clothes.include?(outfitID) + + if !silent + filename = getTrainerSpriteOutfitFilename(outfitID) + name = outfit ? outfit.name : outfitID + unlock_outfit_animation(filename, name) + end + end + + def unlock_hat(hatID, silent = false) + update_global_hats_list() + + hat = $PokemonGlobal.hats_data[hatID] + @unlocked_hats = [] if !@unlocked_hats + @unlocked_hats << hatID if !@unlocked_hats.include?(hatID) + + if !silent + filename = getTrainerSpriteHatFilename(hatID) + name = hat ? hat.name : hatID + unlock_outfit_animation(filename, name) + end + end + + def unlock_hair(hairID, silent = false) + update_global_hairstyles_list() + + hairstyle = $PokemonGlobal.hairstyles_data[hairID] + if hairID.is_a?(Symbol) + hairID = HAIRSTYLES[hairID].id + end + @unlocked_hairstyles = [] if !@unlocked_hairstyles + @unlocked_hairstyles << hairID if !@unlocked_hairstyles.include?(hairID) + + if !silent + filename = getTrainerSpriteHairFilename("2_" + hairID) + name = hairstyle ? hairstyle.name : hairID + unlock_outfit_animation(filename, name) + end + end + + def unlock_outfit_animation(filepath, name, color = 2) + outfit_preview = PictureWindow.new(filepath) + outfit_preview.x = Graphics.width / 4 + musicEffect = "Key item get" + pbMessage(_INTL("{1} obtained \\C[{2}]{3}\\C[0]!\\me[{4}]", $Trainer.name, color, name, musicEffect)) + outfit_preview.dispose + end + + def surfing_pokemon=(species) + @surfing_pokemon = species + end + + def skin_tone=(value) + @skin_tone = value + $scene.reset_player_sprite + #$scene.spritesetGlobal.playersprite.updateCharacterBitmap + end + + def beat_league=(value) + @beat_league = value + end + + def new_game_plus_unlocked=(value) + @new_game_plus_unlocked = value + end + + def seen?(species) + return @pokedex.seen?(species) + end + + # (see Pokedex#owned?) + # Shorthand for +self.pokedex.owned?+. + def owned?(species) + return @pokedex.owned?(species) + end + + def can_change_outfit() + return false if isOnPinkanIsland() + return true + end + + + alias playerAddOns_initialize initialize + def initialize(name, trainer_type) + playerAddOns_initialize(name,trainer_type) + @outfit = 0 + @hat = 0 + @hat2 = 0 + + @hair = 0 + @clothes = 0 + @hair_color = 0 + @skin_tone = 0 + @beat_league = false + @new_game_plus_unlocked = false + @new_game_plus = false + @surfing_pokemon = nil + @last_worn_outfit = nil + @last_worn_hat = nil + @last_worn_hat2 = nil + + @dyed_hats = {} + @dyed_clothes = {} + + @favorite_hat = nil + @favorite_hat2 =nil + @favorite_clothes = nil + + @card_background = Settings::DEFAULT_TRAINER_CARD_BG + @unlocked_card_backgrounds = [@card_background] + @seen_qmarks_sprite = false + + end +end + diff --git a/Data/Scripts/998_InfiniteFusion/Quests/01_quest_reward.rb b/Data/Scripts/998_InfiniteFusion/Quests/01_quest_reward.rb new file mode 100644 index 000000000..0f91f39e3 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Quests/01_quest_reward.rb @@ -0,0 +1,15 @@ +class QuestReward + attr_accessor :item + attr_accessor :quantity + attr_accessor :nb_quests + attr_accessor :description + attr_accessor :can_have_multiple + + def initialize(nb_quests,item,quantity,description,can_have_multiple=false) + @nb_quests =nb_quests + @item =item + @quantity =quantity + @description =description + @can_have_multiple = can_have_multiple + end +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Quests/02_QuestRewards.rb b/Data/Scripts/998_InfiniteFusion/Quests/02_QuestRewards.rb new file mode 100644 index 000000000..b0241f91f --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Quests/02_QuestRewards.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# +# Rewards given by hotel questman after a certain nb. of completed quests +# +QUEST_REWARDS = [ + QuestReward.new(1, :HM08, 1, "This HM will allow you to illuminate dark caves and should help you to progress in your journey!"), + QuestReward.new(5, :AMULETCOIN, 1, "This item will allows you to get twice the money in a battle if the Pokémon holding it took part in it!"), + QuestReward.new(10, :LANTERN, 1, "This will allow you to illuminate caves without having to use a HM! Practical, isn't it?"), + QuestReward.new(15, :LINKINGCORD, 3, "This strange cable triggers the evolution of Pokémon that typically evolve via trade. I know you'll put it to good use!"), + QuestReward.new(20, :SLEEPINGBAG, 1, "This handy item will allow you to sleep anywhere you want. You won't even need hotels anymore!"), + QuestReward.new(30, :MISTSTONE, 1, "This rare stone can evolve any Pokémon, regardless of their level or evolution method. Use it wisely!", true), + QuestReward.new(50, :GSBALL, 1, "This mysterious ball is rumored to be the key to call upon the protector of Ilex Forest. It's a precious relic."), + QuestReward.new(60, :MASTERBALL, 1, "This rare ball can catch any Pokémon. Don't waste it!", true), +] \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Randomizer/RandomizerUtils.rb b/Data/Scripts/998_InfiniteFusion/Randomizer/RandomizerUtils.rb new file mode 100644 index 000000000..69b4537f0 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Randomizer/RandomizerUtils.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +def setRivalStarter(starterIndex1, starterIndex2) + starter1 = obtainStarter(starterIndex1) + starter2 = obtainStarter(starterIndex2) + + ensureRandomHashInitialized() + if $game_switches[SWITCH_RANDOM_WILD_TO_FUSION] # if fused starters, only take index 1 + starter = obtainStarter(starterIndex1) + else + starter_body = starter1.id_number + starter_head = starter2.id_number + starter = getFusionSpecies(starter_body, starter_head).id_number + end + if $game_switches[SWITCH_RANDOM_STARTER_FIRST_STAGE] + starterSpecies = GameData::Species.get(starter) + starter = GameData::Species.get(starterSpecies.get_baby_species(false)).id_number + end + pbSet(VAR_RIVAL_STARTER, starter) + $game_switches[SWITCH_DEFINED_RIVAL_STARTER] = true + return starter +end + +def ensureRandomHashInitialized() + if $PokemonGlobal.psuedoBSTHash == nil + psuedoHash = Hash.new + for i in 0..NB_POKEMON + psuedoHash[i] = i + end + $PokemonGlobal.psuedoBSTHash = psuedoHash + end +end + + +def displayRandomizerErrorMessage() + Kernel.pbMessage(_INTL("The randomizer has encountered an error. You should try to re-randomize your game as soon as possible.")) + Kernel.pbMessage(_INTL("You can do this on the top floor of Pokémon Centers.")) +end + + +def validate_regirock_steel_puzzle() + expected_pressed_switches = [75, 77, 74, 68, 73, 69] + expected_unpressed_switches = [76, 67, 72, 70] + switch_ids = [75, 77, 76, 67, + 74, 68, + 73, 72, 70, 69] + + pressed_switches = [] + unpressed_switches = [] + switch_ids.each do |switch_id| + is_pressed = pbGetSelfSwitch(switch_id, "A") + if is_pressed + pressed_switches << switch_id + else + unpressed_switches << switch_id + end + end + + for event_id in switch_ids + is_pressed = pbGetSelfSwitch(event_id, "A") + return false if !is_pressed && expected_pressed_switches.include?(event_id) + return false if is_pressed && expected_unpressed_switches.include?(event_id) + end + return true +end + +def registeel_ice_press_switch(letter) + order = pbGet(VAR_REGI_PUZZLE_SWITCH_PRESSED) + solution = "ssBSBGG" # GGSBBss" + registeel_ice_reset_switches() if !order.is_a?(String) + order << letter + pbSet(VAR_REGI_PUZZLE_SWITCH_PRESSED, order) + if order == solution + echoln "OK" + pbSEPlay("Evolution start", nil, 130) + elsif order.length >= solution.length + registeel_ice_reset_switches() + end + echoln order +end + +def registeel_ice_reset_switches() + switches_events = [66, 78, 84, 85, 86, 87, 88] + switches_events.each do |switch_id| + pbSetSelfSwitch(switch_id, "A", false) + echoln "reset" + switch_id.to_s + end + pbSet(VAR_REGI_PUZZLE_SWITCH_PRESSED, "") +end + +def unpress_all_regirock_steel_switches() + switch_ids = [75, 77, 76, 67, 74, 68, 73, 72, 70, 69] + regi_map = 813 + switch_ids.each do |event_id| + pbSetSelfSwitch(event_id, "A", false, regi_map) + end +end + +# Solution: position of boulders [[x,y],[x,y],etc.] +def validate_regirock_ice_puzzle(solution) + for boulder_position in solution + x = boulder_position[0] + y = boulder_position[1] + # echoln "" + # echoln x.to_s + ", " + y.to_s + # echoln $game_map.event_at_position(x,y) + return false if !$game_map.event_at_position(x, y) + end + echoln "all boulders in place" + return true +end \ No newline at end of file diff --git a/Data/Scripts/998_InfiniteFusion/Showdown/ShowdownUtils.rb b/Data/Scripts/998_InfiniteFusion/Showdown/ShowdownUtils.rb new file mode 100644 index 000000000..637de9534 --- /dev/null +++ b/Data/Scripts/998_InfiniteFusion/Showdown/ShowdownUtils.rb @@ -0,0 +1,88 @@ +# Clefnair (Clefable) @ Life Orb +# Ability: Magic Guard +# Level: 33 +# Fusion: Dragonair +# EVs: 252 HP / 252 SpD / 4 Spe +# Modest Nature +# - Dazzling Gleam +# - Dragon Breath +# - Wish +# - Water Pulse +def exportFusedPokemonForShowdown(pokemon) + + if pokemon.species_data.is_a?(GameData::FusedSpecies) + head_pokemon_species = pokemon.species_data.head_pokemon + species_name = head_pokemon_species.name + else + species_name = pokemon.species_data.real_name + end + + if pokemon.item + nameLine = _INTL("{1} ({2}) @ {3}", pokemon.name, species_name, pokemon.item.name) + else + nameLine = _INTL("{1} ({2})", pokemon.name, species_name) + end + + abilityLine = _INTL("Ability: {1}", pokemon.ability.name) + levelLine = _INTL("Level: {1}", pokemon.level) + + fusionLine = "" + if pokemon.species_data.is_a?(GameData::FusedSpecies) + body_pokemon_species = pokemon.species_data.body_pokemon + fusionLine = _INTL("Fusion: {1}\n", body_pokemon_species.name) + end + evsLine = calculateEvLineForShowdown(pokemon) + natureLine = "#{GameData::Nature.get(pokemon.nature).real_name} Nature" + ivsLine = calculateIvLineForShowdown(pokemon) + + move1 = "", move2 = "", move3 = "", move4 = "" + move1 = _INTL("- {1}", GameData::Move.get(pokemon.moves[0].id).real_name) if pokemon.moves[0] + move2 = _INTL("- {1}", GameData::Move.get(pokemon.moves[1].id).real_name) if pokemon.moves[1] + move3 = _INTL("- {1}", GameData::Move.get(pokemon.moves[2].id).real_name) if pokemon.moves[2] + move4 = _INTL("- {1}", GameData::Move.get(pokemon.moves[3].id).real_name) if pokemon.moves[3] + + ret = nameLine + "\n" + + abilityLine + "\n" + + levelLine + "\n" + + fusionLine + + evsLine + "\n" + + natureLine + "\n" + + ivsLine + "\n" + + move1 + "\n" + + move2 + "\n" + + move3 + "\n" + + move4 + "\n" + + return ret +end + +def calculateEvLineForShowdown(pokemon) + evsLine = "EVs: " + evsLine << _INTL("{1} HP /", pokemon.ev[:HP]) + evsLine << _INTL("{1} Atk / ", pokemon.ev[:ATTACK]) + evsLine << _INTL("{1} Def / ", pokemon.ev[:DEFENSE]) + evsLine << _INTL("{1} SpA / ", pokemon.ev[:SPECIAL_ATTACK]) + evsLine << _INTL("{1} SpD / ", pokemon.ev[:SPECIAL_DEFENSE]) + evsLine << _INTL("{1} Spe / ", pokemon.ev[:SPEED]) + return evsLine +end + +def calculateIvLineForShowdown(pokemon) + ivLine = "IVs: " + ivLine << _INTL("{1} HP / ", pokemon.iv[:HP]) + ivLine << _INTL("{1} Atk / ", pokemon.iv[:ATTACK]) + ivLine << _INTL("{1} Def / ", pokemon.iv[:DEFENSE]) + ivLine << _INTL("{1} SpA / ", pokemon.iv[:SPECIAL_ATTACK]) + ivLine << _INTL("{1} SpD / ", pokemon.iv[:SPECIAL_DEFENSE]) + ivLine << _INTL("{1} Spe", pokemon.iv[:SPEED]) + return ivLine +end + +def exportTeamForShowdown() + message = "" + for pokemon in $Trainer.party + message << exportFusedPokemonForShowdown(pokemon) + message << "\n" + end + Input.clipboard = message +end \ No newline at end of file diff --git a/Data/messages_core.dat b/Data/messages_core.dat index 89dc9058b32e7c0550110a93cc0864fcbfe832f4..4d40d7194ea7e353893e97fde5b4b804e148caa2 100644 GIT binary patch delta 2434 zcmc(gk8@Pj6~}vC_T7Ci_w8nbh~8Psr~DnA5`&{}F46)V~xhy{m4a4dpFdS4#n>_5=y zn|W_O_j}Ksd(OM(-1D=46yNx`Sg|O}a+XQ?Fu;D^Q}F+Nmj5re@9ppFhrWKPuRo!$ z-!j-QHywj(G9Y$k8a3p4!|#HmX&R{z&rRcXJ;Ul_G@e=zzB`l*zYXhq$kI*lK@v~>3H@R z8SbLoOr~l4nBsMEUwg1M(1EqNEQ1#1vWM@080~zJmC8^^BM-4oN!zY^otkg09tuU) zVs8mc$Nm!bZ@7TnE_OdWLNB{mH^5e!;bu&NH>t3UZ3oDwPdu#10)M9om8=wCH|bTZ z9N+`mRn1!LFr`1`Q6^q1r97$x`(PUNe5RC0P)0}2D?<`&rYFBp>Jp_FGVtJKIn`1u zZOcFyk<${2r5%`jRmpT6O7}V)?nq}xAj=&Mt_iR?KU!EU9WYd1bHv{ouf8VKBv)rN z9522>ZC90x$xus+Eow`S{dt?$Y4^qgZNezhj>GwC8ePa&KeB*Aho`ANDRFbI*O^!z z2?x4xdV!dIpg?UE>hk(xTKEKls{*4x^%syajdX4AQHAtw7` z`l?VMUap|tB6XPrE%?biHGM)zSdFiZMq&YfOvIH{t2cI->%-(IR+mVyk%BI@7+?$T zny>c3PAYJ#6F}OZhuy^>rEYXs}B406d5{tJO4VPCg#G zC?==YsQKw~_hhd#1+Qc~QYqY|K5l^{G}@|8WYQf|us2anr%6$DNk-4!sUjv%RPX4> zs?viY)2CMqu`HywiI9E}2ZiWxb*>r<^aqs;Q&%VwX^S&GV3;oK42J`uIQ2Ed)E5iH zi$3WMLoE;J(O8`6AtBm*;mF!J?a0{jcHJNE)KMYYN`lciySK1rgPHKrzhoVUC#UnpXunTM#1+$d z1LfY!^BL@+nwk6$3Gg0WE989^(CM)vK2?H0(~I+XwIb^x^#gciKA(lp{z)moQ{{X$ ziO-H^*hO7?`2vgjwzw%&PiL$HhX;8EUKr%{umR`p5Q5Av|f9-pVSgZM8nx4s`-|2cuo4+>9g5+P35p5VAWMi$zTN1Z@p!7o?P7E|Pex zv_g8g(VTk%p9^UfBDjBrv|I`HQ&L3B1=x(U+O-$Jfv4NGjj))SR%;4~nA@Y;%A}Ct zi`ReqGL-P2QLRUuoZ{;oi!`3pIz4z>97A01W4X9vG8-=vXcO-2(4G^0r!1zqMZ~{~ zX_uEngu33-mK_BR-+#sy5}vt!ZQIR6BN~0y_G*sus)$)BZEC_JhiwyS=&-G#1bjG7 zve&_E3`q9taFiMn>}RZ^xytrQn*k=uPnS9RR`6hpEu-oJ> z3@$bKqQPY*e`&DC=c;*W@b(SD5^@!3$W=SnK%47*v`Q*9@*Q`MSZ?CVyve zjmb9+t~L3V!4I1ZqS>%IlM@W~nJgQ;&}6H@^(L$7_lm(HbHI&>#U|SfUSe{R!Ang} z#=Q>vT1S`IQ?1fNw+~yU!eslJxlllRs_X+BMOP>}V_#u`Ox!YT55Qz%XYH9;u#U1J P>FjElNC_QDw+{Rl`;x$X delta 2283 zcmYk7e{fXQ6~{d<`|iHC_hmOfnqPpr*@pZe){p^$pwLaS$!5tfLV_d>kSxoZEZJm} z{b9<8L`yTNQvoxIhf*0p=rByFRZ4Rd83Y7rm=aol(N=1upf$D0ZztHe48`+mVAC}*>vg@()7 zdVpP&RKb`e9aEk!UY|;ZZuT5N9v!Y?3rz4wnyg_J0KX(>9jgNPfS##mYphT(bZrF_ z!%Wv!D1kwEfL2~qN+qbEou4YFBtYu?Tv=j)o%rTeB};la3qQFmXCyeKJ$U7+G9}|k zrpJ-w3dJIRyDJ=c+|M4qr^zY3j@e%+Y3YZ=qOB|z?ulPJOf_FA6%0oD>q>J3T zX~L;COR$lu%2g-84t&O?4#HltRj5+|hzcv!EfV~Rj#a7e%8*Mh)TwTm@=(6Vkx~}) z`nv4ypf?inM~txM=i_T%C~0I_tmbD*PZnS@s999osXk?bqcj#&r!gsI2DWoGlS~n{ zIcwn6LXn6&EZ$+S^#+2*YYymQWzgF#^0+G=6k<|YY}K9Y?y4iYX<0B7>W(vgT{mrt z_4N3Iaq1!6v@z3fLDrGrtZZcc&J((|~QJJ3tn51Dd&jslnJ3g?L z`LKSkS;nz#!szxqvxeJL?xCktzQ`nf=)kk9&5vQA#LRJlmG6_0O~4kw?hNbR{;`lb@V10LQ-;_-`4*hkF=c(qAA zDTX*)`h!@0=4gGqED*_eI6IG4_q)g&J*o_NZP>U14uWsK?N~dgv~1xXYOO zFt1iS3n%G6wc0Fz02S72a{(OaTdduHaa!J>T?A0c*{D^d+gcy-IFzzjhq1Q_UkGUV z$v)x2Qt1tZ*BWvMo(X8Xlbs-BS0EY<8S*GSy+->?O8XlZ$NA1Z4tjf58*78Ou3K9q zk~`I{(2b{qUJovRGK zth2}9D>^SS_^Qs;Y~W7sxu#EQjD_nu*BX37=Q@KYb*?w~zdA2A_?FHM2Hzu^7h7Vm zq;sReCY_rMW;!o5Sjj9BlShq-MPFEEu%>gf!B(AH3{Jv*$=3d)9}1sptvC4X&o$A^ z6zk)UKoRY&vkq?(O=sR;tt(BCg