Jump to content

Haru,,

Developers
  • Posts

    137
  • Joined

  • Last visited

  • Days Won

    12

 Content Type 

Profiles

Forums

Events

Reborn Development Blog

Rejuvenation Development Blog

Starlight Divide Devblog

Desolation Dev Blog

Posts posted by Haru,,

  1. Now that the word "debug" is no longer being prohibited in the Discord server, I figure it's high time I release a super trimmed debug mod that will appease the masses and stop them from bricking their saves.

     

    This is a GBA/DS cheat code style mod, with a plethora of features accessed just by hitting the H button by default. All the keybinds are changeable, but only through modifying the mod file itself at the current date.

    Features include:

    Spoiler
    • Party debug (untrimmed)
    • Walkthrough Walls (toggle, O)
    • PC anywhere (keybind, P)
    • Heal anywhere (keybind, I)
    • Infinite money/coins/AP
    • 100% Shiny/Catch rate
    • Rename Trainer
    • Pick Trainer Outfit
    • Warp to maps by ID! (Please save before using this!)
    • More!

     

    Download (You must be signed in!):

    HMD - Cheat Mode.rb

     

    This mod should also work with Desolation, with minor adjustments, namely the outfit picker being tailored explicitly at Rejuv at the moment.

    • Like 2
    • Thanks 5
  2. Miscellaneous Info

    Here I'll explain a little more on how hashes work and some other features that I'll add to later down the line if I can think of anything.

     

    Hashes

    Hashes are just a super fancy array in essence. They're definitely not a replacement for arrays, as each have their own use, but they are much better for storing large quantities of data as they have keys that point to data rather than simple integers. An example of this would be your hash containing every bit of Pokemon data. Sure, some are fine with remembering all 900+ dex numbers and know that number 492 is Shaymin and 156 is Quilava. But many aren't! I wish there was way to tell the data that I want Quilava data and it gives us Quilava data instead of having to tell it "Give me data entry 156!" That's where hashes come from. 

    They're broken down into two parts: a key and a value. The key can be any value of integer, string, symbol, or even user defined class. However that class must have implemented the hash and eql? functions. The value can be any syntactically correct value: variables, hashes, objects, integers, strings, booleans, etc.

    If you're trying to create storage for a few values it might be better to use an array as they use less space than a hash. However hashes are much more readable than arrays for bigger cases.

     

    Aliasing

    Aliasing is another very powerful tool in Ruby. It's best to think of it along the lines of overloading a method. Its main use though is hijacking a method to add code before or after the method would usually end.

    We can set up an alias in two different ways:

    alias new_name old_method 

    This one is used outside of a class or module for generic methods. An example of such is as follows:

    def dothis
        print "I did this" 
    end
    dothis
    # Output: I did this
    
    alias didthat dothis
    
    def dothis
        didthat
        print " with aliasing"
    end
    dothis
    # Output: I did this with aliasing

    The most immediately relevant connection to the games I can make is our achievement system. They all alias various methods to have them process normally, then make changes to achievements in the same method.

    An example of it running code before hand is a quick little randomizer I had written up on Rejuv V13.5's release:

    class PokeBattle_Pokemon
      alias __core_init initialize
      def initialize(*args)
        args[0] = $cache.pkmn.keys[rand($cache.pkmn.length)-1]
        __core_init(*args)
      end
    end

    This will override the initialize method, change the species being passed, and then continue as normal.

     

    The other method of aliasing is for modules:

    module The
        def self.output
            puts "Output 1"
        end
        
        self.singleton_class.send(:alias_method, :output1, :output)
        
        def self.output
            puts "Output 2"
        end
    end
    
    The.output1
    The.output
    
    # Output: Output 1
    #         Output 2

    Modules work a little differently than classes, so any public methods like these must use the send method to alias them. As shown above, it is not required to used the old method in the new definition and you can even use the old method any time you like, not contained to the class/module you're modifying through alias. Where this gets super handy is for making even more modular mods. Mod authors don't need to combine methods to make a "Compatibility Patch" and instead just need to work around each others methods. 

    The general naming syntax used from Essentials and thus adopted by us is __core_methodName. You'll have seen in some of my later Reborn/Rejuv mods for the last version that I had used __hmd_methodName. In reality it doesn't really matter what you use. 

     

    Parameters

    You'll notice above I used a weird parameter for the method signature. *args. To explain this, we'll need to break down method parameters a little bit more.

    Method parameters will take any value on a 1 to 1 basis, with defined names for each value. But some times, you don't know how many arguments a user will input. That's where we use *args, also known as a splat operator. A splat operator essentially transforms an array into arguments matching the parameters of the method, provided it does not go past the amount of parameters defined. args is just a regular array without the splat operator as well, meaning you can modify it as you would a regular array. To reuse in an aliased method you must reinclude the splat operator.

    Parameters throughout our code also make use of default values, for when the user does not pass an argument. An easy example of this is our method:

    def Kernel.pbItemBall(item,quantity=1,pural=nil); ...; end

    This means our method is expecting anywhere from 1 to 3 arguments. If we give 0, then it will break, if we give 4, then it will break, If we only give the first parameter, then the method will default quantity to 1 and plural to nil.

    There's also another way of adding in optional parameters, which was added in Ruby 2.0 (original Essentials runs on Ruby 1.8.1):

    def myMethod(optional: false)
    	puts optional
    end
    
    myMethod 
    # Ouput: false
    myMethod(true)
    # Output: true

    This is more in line with JSON object notation, which you may be more familiar with.

     

    • Like 1
  3. Defining a Boss

    Bosses are the capstone of our work on Rejuvenation. They're defined in BossInfo.rb and compiled by compileBosses

    Once again, like :trainereffects from Trainers above, they are already heavily detailed inside the first boss template, so I will not be explaining them here.

    I've made a custom boss that will make a little more sense once we get through our custom shield break mechanic.

    Spoiler
    :BOSSZAPDOS => {
      :name => "Zapdos",
      :entryText => "Zapdos descends from the clouds!",
      :shieldCount => 1,
      :immunities => {},
      :moninfo => {
        :species => :ZAPDOS,
        :level => 100,
        :moves => [:THUNDER,:ETHEREALTEMPEST,:ROOST,:DISCHARGE],
        :gender => "F",
        :nature => :MODEST,
        :ability => :VOLTABSORB,
        :iv => 31,
        :happiness => 255,
        :ev => [252,252,252,252,252,252]
      },
      :onEntryEffects => { 
        :fieldChange => :ELECTERRAIN,
        :fieldChangeMessage => "Zapdos's energy courses through the field!"
      },
      :onBreakEffects => {
        1 => {
          :threshold => 0,
          :animation => :DISCHARGE,
          :paralyzePlayer => true,
          :statDropCure => true,
          :fieldChange => :MOUNTAIN,
          :fieldChangeMessage => "Zapdos's energy erupts!"
        }
      }
    },

    After that you can compile. You'll see a new key there in the break effects, :paralyzePlayer. Let's go ahead an code that in.

     

    For our purposes, we'll be looking for the file PokemonBossBattle.rb, and the method pbShieldEffects. To avoid clashing with anything else, we'll be adding our new effect after any stat changes but before any :CustomMethod handling. Quickly, since custom methods aren't explained, you can write some code and throw it in a string, then our break effect handling will run that code. It's a very powerful tool and used for one of our....mechanics. You'll see if you look a little into it but we recommend not doing that!

    Anyway, Time for our code:

    Spoiler
    if onBreakdata[:paralyzePlayer]
      for i in @battlers
        next if !i.pbCanParalyze?(false)
        next if !battler.pbIsOpposing?(i.index)
        i.pbParalyze(battler)
      end
      for i in @party1
        i.status = :PARALYSIS if i.status.nil? && !(i.ability == :LIMBER || i.hasType?(:ELECTRIC))
      end
      @scene.pbRefresh
      pbDisplay("The electricity paralyzed your team!")
    end

    This will look through every active battler, check if it can paralyze, check if its your Pokemon, then paralyze them. Then it will iterate through your party and attempt to paralyze those as well.

     

    You'll also need to be able to fight these bosses. There's actually two different ways of doing so: through a wild battle and through a trainer. For a wild battle you simply need to call the boss name through the regular call like so:

    pbWildBattle(:BOSSZAPDOS,1)

    The level (the number there) does not matter as everything about the Pokemon will be pulled from the boss data. This applies to trainers too. In place of a Pokemon you can simply add in the :boss key where the value is the name of the boss. I strongly recommend putting in basic information there for clarity's sake, though. After that you'd make a call to battle a trainer and it would send out the boss all the same.

     

    Spoiler

    image.png.bdc758c880f83cf989d79338fae699d1.pngimage.png.3962e8210d9434b22584e56260ccdb9d.png

     

    • Like 1
  4. Defining a Trainer

    Trainers are the most complicated of the DOH, excluding bosses, while also being the easiest to create. Trainer definitions can be found in trainertext.rb.

     

    Trainers are defined as an array of hashes, where each hash has 6 components:

    • :teamid - An array of the trainer name, class, and identifier for matching names/classes.
    • :items - An array of items the trainer has access to in battle
    • :ace - A string displayed in battle when the trainer sends out their last Pokemon
    • :defeat - A string displayed at the end of battle when the trainer is defeated
    • :mons - An array of hashes containing data for each Pokemon. Attributes such as species, level, ability, item, moves, nature, EVs, happiness, and IVs may be changed. IVs will be spread across the board, and an IV value of 32 is used for Trick Room teams to give a 0 speed IV while the rest are 31.
    • :trainereffect - A hash which contains effects similar to bosses. These are explained at the top of Rejuvenation's trainertext.rb so I will not be diving into them here. If you'd like to expand on these I will be adding a new break effect on bosses, which should provide insight as to what you're expected to look for to add a new effect here.

    Trainers are compiled via the line compileTrainers, and called via pbTrainerBattle or pbDoubleTrainerBattle. Each of their parameters can be found by looking at their definitions.

     

    Trainer Classes

    Classes are what makes a trainer a trainer. They contain all sorts of useful information, and can be found in ttypetext.rb. These do in fact have a symbol identifier, and can be named anything. The following is the list of attributes that can be used:

    • :ID - The number assigned to the trainer's graphic in the Graphics/Characters folder, following the word "trainer"
    • :title - The display name of the trainer class
    • :skill - the level of AI used out of 100, default 30
    • :moneymult - the multiplier of money earned based on the trainer's highest level Pokemon, default 30
    • :trainerID - An override of the PokeBattle_Trainer object trainerID. Used exclusively for flavor.
    • :battleBGM - A string containing the name of the battle music for the trainer, found in Audio/BGM
    • :winBGM - A string containing the name of the victory music for the trainer, found in Audio/BGM
    • :player - A boolean based on if the trainer is a playable character. 

    Once again, given the skill you can add anything you want here. Trainer classes are compiled by compileTrainerTypes.

    • Like 1
  5. Adding a Pokemon

    Probably the most drastic change from previous versions, Pokemon are now easier than ever to implement.

    Pokemon species and forms are now located inside the file montext.rb, a much more graceful solution than two separate files or one file and not easily modifiable at all.

     

    Creating a New Pokemon

    To start, open up montext.rb inside your workspace, located in your specific game's subfolder.

    We'll discuss the structure for a Pokemon first. Each field is broken down in the code block below, with further explanation where needed afterwards.

    Spoiler
    :VENUSAUR => {							# Species name. Identifier when calling information.
    	"Normal Form" => {					# Form name. 
    		:name => "Venusaur",				# Display name
    		:dexnum => 3,					# Pokedex number
    		:Type1 => :GRASS,							
    		:Type2 => :POISON,
    		:BaseStats => [80, 82, 83, 100, 100, 80],	# Base stats, sorted HP/Attack/Defense/Special Attack/Special Defense/Soeed
    		:EVs => [0, 0, 0, 2, 1, 0],			# EV yield
    		:Abilities => [:OVERGROW, :CHLOROPHYLL],	# See after for hidden abilities
    		:GrowthRate => :MediumSlow,			# EXP Curve. See after for all values.
    		:GenderRatio => :FemEighth,			# Male/Female ratios. See after for all values.
    		:BaseEXP => 236,							
    		:CatchRate => 45,							
    		:Happiness => 70,				# Base happiness when caught
    		:EggSteps => 5355,				# Steps required to hatch
    		:preevo => {					# Values to store pre-evolution. Added to make it easy to get pre-evolution data.
    			:species => :IVYSAUR,
    			:form => 0
    		},
    		:Moveset => [					# Learnset. Stored as [level, move symbol]. 0 is learned on evolution.
    			[0,:PETALDANCE],
    			[1,:TACKLE],
    			[1,:GROWL],
    			[1,:LEECHSEED],
    			[1,:VINEWHIP],
    			[3,:GROWL],
    			[7,:LEECHSEED],
    			[9,:VINEWHIP],
    			[13,:POISONPOWDER],
    			[13,:SLEEPPOWDER],
    			[15,:TAKEDOWN],
    			[20,:RAZORLEAF],
    			[23,:SWEETSCENT],
    			[28,:GROWTH],
    			[31,:DOUBLEEDGE],
    			[39,:WORRYSEED],
    			[45,:SYNTHESIS],
    			[50,:PETALBLIZZARD],			# Below is every move that can be learned by the species from TM or tutor. 
    			[53,:SOLARBEAM]],			# Egg moves are stored specifically within the first stage of the Pokemon.
    		:compatiblemoves => [:AMNESIA,:BIDE,:BIND,:BLOCK,:BODYSLAM,:BULLDOZE,:BULLETSEED,:CELEBRATE,:CHARM,:CURSE,:CUT,:DEFENSECURL,:DOUBLEEDGE,:EARTHPOWER,:EARTHQUAKE,:ECHOEDVOICE,:ENERGYBALL,:FALSESWIPE,:FLASH,:FRENZYPLANT,:FURYCUTTER,:GIGADRAIN,:GIGAIMPACT,:GRASSKNOT,:GRASSPLEDGE,:GRASSYGLIDE,:GRASSYTERRAIN,:HEADBUTT,:HELPINGHAND,:HYPERBEAM,:KNOCKOFF,:LEAFSTORM,:LIGHTSCREEN,:MAGICALLEAF,:MEGADRAIN,:MIMIC,:MUDSLAP,:NATUREPOWER,:OUTRAGE,:POWERWHIP,:RAGE,:RAZORWIND,:REFLECT,:ROAR,:ROCKCLIMB,:ROCKSMASH,:SAFEGUARD,:SEEDBOMB,:SKULLBASH,:SLUDGEBOMB,:SOLARBEAM,:STOMPINGTANTRUM,:STRENGTH,:STRINGSHOT,:SUNNYDAY,:SWEETSCENT,:SWORDSDANCE,:SYNTHESIS,:TAKEDOWN,:TERRAINPULSE,:VENOSHOCK,:WEATHERBALL,:WORKUP,:WORRYSEED,]
    		:moveexceptions => [],				# There is an array called PBStuff::UNIVERSALTMS that almost any Pokemon learns. Add those moves here if you want to exclude them from a Pokemon.
    		:Color => "Green",				# Flags for color and habitat sorting in Pokedex, which I'm not actually sure are used
    		:Habitat => "Grassland",
    		:EggGroups => [:Monster, :Grass],		# Egg Groups
    		:Height => 20,					# Height and weight are metric based times 10. Venusaur is 2 meters 100 kilo
    		:Weight => 1000,
    		:kind => "Seed",				# Pokedex descriptor and dex entry
    		:dexentry => "Venusaur's flower is said to take on vivid colors if it gets plenty of nutrition and sunlight. The flower's aroma soothes the emotions of people.",
    		:BattlerPlayerY => 16,				# Positioning values
    		:BattlerEnemyY => 15,
    		:BattlerAltitude => 0,
    	},
    
    	"Mega Form" => {					# Another form name
    		:BaseStats => [80, 100, 123, 122, 120, 80],	# EVERY single flag used can be changed for forms, except for dex number.
    		:Abilities => [:THICKFAT],
    		:BaseEXP => 281,
    		:Height => 24,
    		:Weight => 1555,
    	},
    
    	"Giga Form" => {
    		:BaseStats => [80, 107, 108, 125, 125, 80],
    		:Abilities => [:CHLOROPHYLL],
    		:Height => 240,
    		:Weight => 2216,
    	},
    
    	:OnCreation => {},					# The proc for changing forms/stats/anything when creating the Pokemon in game. See after for info.
    	:DefaultForm => 0,					# Stores the default forms (can be array, see Toxtricity/Urshifu) for checking if the mon can mega/primal/rift/pulse evo.
    	:MegaForm => {						# Stores the resulting form for mega/primal/rift/pulse evo based on held item.
    		:VENUSAURITE => 1,
    		:VENUSAURITEG => 2,
    	},
    },

     

    Hidden Abilities are not actually implemented in Rebornverse games, however the ability to add them does exist if you wanted to override our hidden ability override. You'll see some Pokemon use the :HiddenAbility flag. Abilities in this flag are automatically added to the ability list and do not count as real hidden abilities.

    Growth Rates can be the following values: :Erratic, :Fluctuating, :MediumSlow, :Fast, :MediumFast, :Slow. Further info about these can be gained from sites like Bulbapedia.

    Gender Ratios can be the following values: :Genderless, :MaleZero, :FemZero, :FemEighth, :FemQuarter, :FemHalf, :MaleQuarter. These values are, in order: Genderless, Always Female, Always Male, 1/8th Female, 1/4th Female, 50/50, 1/4th Male.

     

    The creation changing is really useful! It was mainly used to generalize generating regional forms. We use them only for returning form number, but they can be used for a lot of neat things and I'm interested in seeing what you guys can come up with.

    The general formatting is such:

    :OnCreation => proc{
      	next $game_map && Rattata.include?($game_map.map_id) ? 1 : 0
    },

    We check to make sure $game_map is defined and then check if the current map id matches those included in each regional form array defined in the file SystemConstants.rb found in the game-specific subfolder. 

     

    We'll add a new Pokemon called Beatote, created by the spriter Samson on PokeCommunity, which is free to use. You likely will be unable to find these sprites without ripping them out of GBA games that already have them. Again, the provided images are located at the start of the thread.

    These must be named with their dex number, with their respective Battler, Icon, and SE files.

    Next, you'll need to fill out the Pokemon data. I'll provide the fully written out one here.

    Spoiler
    :BEATOTE => {
    	"Normal Form" => {
    		:name => "Beatote",
    		:dexnum => 906,
    		:Type1 => :BUG,
    		:Type2 => :LIGHT,
    		:BaseStats => [75, 85, 110, 50, 95, 80],
    		:EVs => [0, 0, 2, 0, 0, 0],
    		:Abilities => [:ILLUMINATE, :SWARM],
    		:HiddenAbilities => :FLUORESCENT,
    		:GrowthRate => :Erratic,
    		:GenderRatio => :FemZero,
    		:BaseEXP => 184,
    		:CatchRate => 45,
    		:Happiness => 70,
    		:EggSteps => 4080,
    		:preevo => {
    			:species => :VOLBEAT,
    			:form => 0
    		},
    		:Moveset => [
    			[0,:PHOTONSLASH]
    			[1,:FLASH],
    			[1,:TACKLE],
    			[5,:DOUBLETEAM],
    			[8,:CONFUSERAY],
    			[12,:QUICKATTACK],
    			[15,:STRUGGLEBUG],
    			[19,:MOONLIGHT],
    			[22,:TAILGLOW],
    			[26,:SIGNALBEAM],
    			[29,:PROTECT],
    			[33,:ZENHEADBUTT],
    			[36,:HELPINGHAND],
    			[40,:BUGBUZZ],
    			[43,:PLAYROUGH],
    			[47,:DOUBLEEDGE],
    			[50,:INFESTATION]],
    		:compatiblemoves => [:PHOTONSLASH,:AIRSLASH,:DRAININGKISS,:FAKETEARS,:MAGICALLEAF,:POLLENPUFF,:POWERGEM,:SKITTERSMACK,:BATONPASS,:DOUBLEEDGE,:MIMIC,:ACROBATICS,:AERIALACE,:AIRCUTTER,:BODYSLAM,:BRICKBREAK,:BUGBITE,:BUGBUZZ,:CHARGEBEAM,:COUNTER,:DAZZLINGGLEAM,:DEFOG,:DYNAMICPUNCH,:ENCORE,:FLASH,:FLING,:FOCUSPUNCH,:GIGADRAIN,:HELPINGHAND,:ICEPUNCH,:INFESTATION,:LIGHTSCREEN,:MEGAKICK,:MEGAPUNCH,:METRONOME,:MUDSLAP,:OMINOUSWIND,:PLAYROUGH,:POWERUPPUNCH,:PSYCHUP,:RAINDANCE,:ROOST,:SEISMICTOSS,:SHADOWBALL,:SHOCKWAVE,:SIGNALBEAM,:SILVERWIND,:SOLARBEAM,:STRINGSHOT,:STRUGGLEBUG,:SUNNYDAY,:SWIFT,:TAILWIND,:THIEF,:THUNDER,:THUNDERBOLT,:THUNDERPUNCH,:THUNDERWAVE,:TRICK,:UTURN,:WATERPULSE,:ZENHEADBUTT,
    			#Rejuv only moves
    			:IRRITATION,:STACKINGSHOT],
    		:moveexceptions => [],
    		:Color => "Gray",
    		:Habitat => "Forest",
    		:EggGroups => [:Bug, :HumanLike],
    		:Height => 14,
    		:Weight => 423,
    		:WildItemUncommon => :BRIGHTPOWDER,
    		:kind => "Ground Fly",
    		:dexentry => "Beatote live underground, taking over the colonies of the Nincada that live in the area by blinding them.",
    		:BattlerPlayerY => 23,
    		:BattlerEnemyY => 19,
    		:BattlerAltitude => 0,
    	},
    
    	:OnCreation => {},
    },

     

     

    After that you can compile via compileMons and give yourself a new Beatote! The Pokedex will get automatically updated if it detects there are more species in the DOH than in the Pokedex itself. For custom forms, you'll need to manually refresh the Pokedex.

    Spoiler

    image.png.6f5f0efe0796e1c3cf45a74746140edc.pngimage.png.03f5b9afe87fcf747f27a2e56464d5bd.png

     

    Adding a Form

    We've successfully added a new Pokemon with a new type. But how can you add a new type without having Arceus's approval? Let's help them out.

    We're going to do a little cheating and instead of having the plate/Z-Crystal change Arceus's type, we'll change the form based on if you have a Light-type Pokemon or move in your party when encountering it.

     

    Unfortunately, though, Arceus (and Silvally) signature moves are tied to their items at the moment. So, we're going to need to override that. Back in Battle_MoveEffects.rb, we need to find PokeBattle_Move_09F. We'll need to throw in a check for our new Arceus form in the pbType method like such:

    if attacker.species == :ARCEUS && $cache.pkmn[:ARCEUS].forms[attacker.form] == "Light"
      return super(attacker,:LIGHT)
    end

    This should go before any check to avoid needless chance to write over things we aren't accounting for.

     

    After that we can go back to montext.rb and define the new form:

    Spoiler
    "Light" => {
      :Abilities => [:FLUORESCENT],
      :Type1 => :LIGHT,
    },
    
    :OnCreation => proc{
      next 0 if !$Trainer
      foundLight = false
      for mon in $Trainer.party
        if mon.type1 == :LIGHT || mon.type2 == :LIGHT
          foundLight = true
          break
        end
        for move in mon.moves
          if move.type == :LIGHT
            foundLight = true
            break
          end
        end
        break if foundLight
      end
      next $cache.pkmn[:ARCEUS].forms.invert["Light"] if foundLight
      next 0
    },

    You should be removing the current :OnCreation attribute already there with this one. This proc will check your party for the above defined conditions and return the form that Light is assigned to.

    You'll want to compile one more time and then your beautiful Light-type Arceus works!

    Spoiler

    image.png.4397f1808fdc42f21d2db63d94cec8d7.pngimage.png.212bab757d98e27733eec4c927b994ab.png

     

    You can do a lot of fun stuff with procs. If you are so inclined, you can even add a new proc to them (make sure you follow my handling of :OnCreation procs!!!!!) and pass in the Pokemon object itself and make direct edits to it if you so desired. Very similar to how EncounterModifier works, actually. I wouldn't recommend this though as handling the dat files of the games is very finnicky if you don't know what you're doing.

     

    Were you not loaded into a save when you compiled? No worries! You can just run the command:

    $Trainer.pokedex.refreshDex

    to refresh every dex entry, or:

    $Trainer.pokedex.updateGenderFormEntries

    to update specifically forms/genders of existing dex entries.

     

    With that, we've covered the basics of modding for the Rebornverse games. Next we will get into bosses, trainers, and extra coding tips!

    • Like 1
  6. Adding an Ability

    Abilities are where it starts to get...complicated. If you want to properly set things up you'll need to modify the AI and Battle files for them to work properly. Fortunately, we can kind of cheat. If you're trying to make a new ability, chances are that some ability accomplishes a similar thing, and we can find where those abilities activate and insert our own. Before we code in an ability, let's break down ability application in Battle_Move.rb with the function pbCalcDamage.

    Spoiler
    1. Initialize various variables, including pulling the base damage from the DOH.
      1. Modify base damage if Luvdisc crest or for a move function that directly modifies pbBaseDamage
    2. Escape if still no base damage, then check crit chance, initialize boost stages, and get the type of the move user
    3. Check if items work
    4. Check abilities that modify move power (not pokemon stats, although they are technically equivalent)
    5. Check opponent ability for things like Heatproof/Dry Skin
    6. Check for items such as type boosting items, gems, other items that affect base damage (Soul Dew, Lustrous Orb, Wise Glasses)
    7. Check if the move function modifies pbBaseDamageMultiplier (Fusion Bolt, Facade, Solar Beam)
    8. Check crests
    9. Check the typing based on effects that modify move power (Charge, Water Sport, Fairy Aura, Helping Hand)
    10. Apply field effect modifiers
    11. Calculate attackers stats (Foul Play, Body Press, Glitch field, stat boosts, Unaware, Claydol/Dedenne Crest)
      1. Pinch Abilities, stat modifying abilities, mid battle crests.
      2. Weather
      3. Items and field effects that affect stats
    12. Calculate opponent defense
      1. Sandstorm
      2. Abilities that modify defense
      3. Items that modify defense
    13. Spread move debuff
    14. More field effects
    15. Field transformations
    16. More crests, for extra STAB this time
    17. Regular STAB
    18. Type effectiveness
    19. Damage rolls
    20. Final damage multipliers
      1. Screens, Tinted Lens, Multiscale, Solid Rock, Type Berries, other crests
    21. More multipliers for the final final time, through overriding pbModifyDamage
      1. Minimize counters, two-turn move catchers (Gust/Hurricane vs Fly, Surf vs Dive)
    22. The actual real damage calculation.

    It's. A lot. And some of it seems counter productive! But it's the beautiful thing we get to work with. So. New ability time. 

     

    We'll make a new ability that empowers Light type moves in preparation for our new Pokemon being added later. To do that, we need to crack open abiltext.rb and define our new ability, like so:

    Spoiler
    :FLUORESCENT => {
    	:ID => 268,
    	:name => "Fluorescent",
    	:desc => "Powers up Light-type moves...",
    	:fullDesc => "Light-type moves used by the user increase in power by 20%"
    },

     

    You'll notice two new flags inside this file, :fulldesc and :fullname. These are used for the expanded summary screen. When on the Stats summary page, you can press [C], or whatever your rebinded "A" button is, to view an expanded name and description if one is provided. The team has largely used this to detail exact values for abilities. IDs are also largely irrelevant, still a leftover from the old ID systems, but if you need them they free up at ID 268 as of writing this post, and then again at whatever value the custom abilities per game stop at.

    Once that's added, you can compile via compileAbilities.

     

    Now we'll need to code in this ability. For our case, we're heading to Step 4 as detailed above. Anywhere in that first run through of abilities we can add in the line:

    when :FLUORESCENT   then basemult*=1.2 if @type==:LIGHT

    Once we're done with this we do not need to do anymore work, however if you intend to properly balance things we need to make edits to the AI as well in the file Battle_AI.rb. The AI is far too large for me to detail in this post, but here's the part where we look for abilities that have similar effects and copy their code for our needs. Luckily, we only need to add a few lines of code to a single section for this ability. We'll be editing where STAB is calculated in the AI for when it gets move scoring. A little of the way down you'll see calculations for Water Bubble, Adaptability, and Steelworker. We'll be adding our code there, or more specifically, copying Water Bubble's code and changing it for Fluorescent.

    Spoiler
    # Fluorescent
    if attacker.ability == :FLUORESCENT && type == :LIGHT
      damage=(damage*=1.2).round
    end

    The AI now properly gets the damage information when a Pokemon has Fluorescent. There is tons of AI nonsense to look through if you want to really balance something, and a good chunk of it is fields. Try checking out what abilities, fields, and moves effect which parts of the AI scores if you're looking for more information.

    • Like 1
  7. Adding an Item

    Items are another straightforward process thanks to our changes to the code. In here we'll be adding 3 different items. A Z-Crystal, a TM, and a battle item. The same processes apply to all items and just need certain flags to function as such.

    First, we can find all our items in itemtext.rb (Are you beginning to see a pattern here?). Here is all the flags for items:

    Spoiler
    :ID		# Internal item ID. Used to be used for graphics
    :name		# Item display name
    :desc		# Item description
    :price		# Buying price
    :overworld	# Whether the item can be used in overworld
    :noUseInBattle 	# Whether the item cannot be used in battle
    :noUse		# Whether the item has no use
    :evoitem	# Whether the item is an evolution item
    :fossil		# Whether the item is a fossil
    :justsell	# Whether the item is a "collector" item {Rare Bone, Relic Gold, etc)
    :consumehold	# Whether the item gets consumed on use in battle
    :battlehold	# Whether the item has a hold effect in battle
    :incense	# Whether the item is an incense item
    :typeboost	# The type as a symbol of what type it boosts when held/consumed
    :plate		# Whether the item is a plate
    :memory		# If the item is a Silvally memory, it stores the typing corresponding to the item
    :gem		# Whether the item is a gem
    :mint		# Whether the item is a mint
    :utilityhold	# Whether the item has an overworld effect when held (Magnetic and Mirror Lures)
    :pokehold	# Whether the item boosts a specific non-legendary Pokemon
    :legendhold	# Whether the item boosts a specific legendary Pokemon
    :application	# Whether the item is an application item (Reborn)
    :nectar		# Whether the item is a nectar item (Oricorio)
    :quest		# Whether the item is a quest item
    :mail		# Whether the item is a mail item
    :medicine	# Whether the item goes in the Medicine pocket
    :healing	# Whether the item has a healing effect
    :revival	# Whether the item has a reivival effect
    :status		# Whether the item cures status
    :pprestore	# Whether the item restores PP
    :evup		# Whether the item raises EVs
    :levelup	# Whether the item grants EXP
    :ball		# Whether the item goes in the Ball pocket
    :tm		# Whether the item goes in the Machines pocket
    :berry		# Whether the item goes in the Berry pocket
    :pinchberry	# Whether the item is a pinch berry
    :resistberry	# Whether the item is a resistance berry
    :battleitem	# Whether the item goes in the Battle Items pocket
    :crystal	# Whether the item goes in the Enhancement Pocket
    :crest		# Whether the item is a crest
    :zcrystal	# Whether the item is a Z-Crystal
    :keyitem	# Whether the item goes in the Key Item pocket
    :legendary	# Whether the item changes forms of Pokemon
    :evCard		# Whether the item grants access to the EV Training Center Rooms (Rejuv)
    :general	# Literally just the Remote PC I honestly don't know
    :important	# Whether the item cannot be sold
    :niche		# Whether the item is niche (Powder Vial, Devon Scope, PokeFlute)
    :keys		# Whether the item is a key (Reborn)
    :story		# Whether the item is a story item
    :sidequest	# Whether the item is a sidequest item

     

    Once again, they follow the standard procedure of having a symbol identifier for the item. You can also add your own flags to say that X group of items are from a specific mod. 

     

    For our items, we'll create them here. We need a Z-Crystal for Light type moves, a TM for them, then a status item. I've written the code here:

    Spoiler
    :LIGHTINIUMZ => {
    	:ID => 1106,
    	:name => "Lightinium-Z",
    	:desc => "It converts Z-Power into crystals that upgrade Light-type moves to Light-type Z-Moves.",
    	:price => 0,
    	:crystal => true,
    	:zcrystal => true,
    	:noUseInBattle => true,
    },
    
    :TM158 => {
    	:ID => 1107,
    	:name => "TM158",
    	:desc => "The target is struck with a condensed beam of light. May lower defense. Uses higher attack stat.",
    	:price => 25000,
    	:tm => :PHOTONSLASH,
    	:noUseInBattle => true,
    },
    
    :XRESET => {
    	:ID => 1108,
    	:name => "X Reset",
    	:desc => "Removes all negative stat changes.",
    	:price => 500,
    	:battleitem => true,
    	:noUse => true,
    },

     

    After that you can compile with compileItems and you'll be able to give yourself items via the command Kernel.pbItemBall(:ITEM), where :ITEM is replaced by the symbol you added.

    Lightinium-Z does not need any further implementation. Our TM needs to be added to the :compatiblemoves attribute of any Pokemon you'd like to learn it, which will be discussed later.

     

    The Reset X however does need its full implementation still. We'll be revisiting ItemEffects.rb for this. To explain this file, we need to know a few things. Items use what are known as ItemHandlers. This module is defined in Items.rb and contains all the relevant information we need. There are 6 handlers and 1 extra constant for items you can use multiple of at once. Out of the six handlers; UseFromBag, UseInField, UseOnPokemon, BattleUseOnBattler, BattleUseOnPokemon, and UseInBattle, the one we're interested in BattleUseOnBattler. These handlers are all self explanatory, except for maybe the difference of the battle handlers. BattleUseOnBattler applies to the active Pokemon, BattleUseOnPokemon pull up the party menu in battle, and UseInBattle is for items that affect the field/enemy. 

    Anyway, we'll need to add an effect for our X Reset. The parameters for every item handler is the symbol for the item and a lambda, which is similar to a proc (which will be explained later) except that it only yields values true or false. I've gone ahead and written the code already so you can use it as an example, but each handler uses a different amount of parameters for the lambda. The item itself, the battler, which is a derivative of the Pokemon object used for battles, and the battle scene, which is used to play animations and send messages to the battle scene. The code is as follows:

    Spoiler
    ItemHandlers::BattleUseOnBattler.add(:XRESET,lambda{|item,battler,scene|
       playername=battler.battle.pbPlayer.name
       itemname=getItemName(item)
       scene.pbDisplay(_INTL("{1} used the {2}.",playername,itemname))
       oldStages = battler.stages.clone
       for i in PBStats.constants
         next if i == 0
         stat = PBStats.const_get(i)
         battler.stages[stat] = 0 if battler.stages[stat] < 0 
       end
       if oldStages == battler.stages
        scene.pbDisplay("But it had no effect!")
         return false
       end
       scene.pbDisplay("#{battler.pbThis}'s stats were reset!")
       return true
    })

     

    Since this is strictly scripting, we have nothing to compile. These changes take place immediately. And now you've written some items! I'm sure you can figure out the other kinds of items by trial and error.

    • Like 2
  8. Adding a Move

    Moves are fairly simple to add, but get a little extra complicated as you dive deeper. Let's start by breaking down all the flags a move can have.

    Similar to the above, every move is defined by a symbol for their identifier and flags, as shown by the other moves in movetext.rb. Those flags are:

    Spoiler
    :ID		# Almost exclusively used for conversion, unneeded otherwise
    :name 		# The shortened name for display
    :longname	# The full name, for moves like Light That Burns the Sky. Used in battle exclusively.
    :desc		# The move description
    :type		# The move typing
    :category	# Physical/special/status
    :basedamage	# See later for info
    :accuracy	# See later for info
    :maxpp		# Default max PP, using a PP Max is automatically calculated
    :target		# See later for info
    :function	# See later for info
    :contact	# Whether the move makes contact
    :kingrock	# Whether the move is affected by King's Rock
    :effect		# The percent chance for an effect to trigger
    :highcrit	# Whether the move has a high crit ratio
    :soundmove	# Whether the move is sound based
    :sharpmove	# Whether the move is Sharpness boosted
    :beammove	# Whether the move is a beam move (Claydol Crest)
    :snatchable	# Whether the move is affected by Snatch
    :nonmirror	# Whether the move can be pulled by Mirror Move
    :healingmove	# Whether the move heals
    :magiccoat	# Whether the move is reflected by Magic Coat
    :recoil		# The damage ratio as a decimal for recoil damage
    :punchmove	# Whether the move is Iron Fist boosted
    :moreeffect	# The percent change for a secondary effect to trigger (Think Fire Fang flinch/burn)
    :gravityblocked	# Whether a move gets blocked by gravity
    :defrost	# Whether a move immediately defrosts freeze
    :bypassprotect	# Whether a move ignores Protect
    :windmove	# Whether a move is a wind based move (Flag used by the Genies?
    :heavymove	# Whether the move can be used twice in a row (Gigaton Hammer, Decimation)
    :zmove		# Whether the move is a Z Move
    :intercept	# Whether the move is a Interceptor move (Rejuv)

    Base Damage can be any value. Values of 0 are reserved for status moves and values of 1 are reserved for moves with custom damage formulas such as Dragon Rage, Heavy Slam, and Nature's Madness.

    Accuracy can also be any value. Values of 0 are moves that bypass the accuracy check.

    Target is for selecting targets in double battles. These values are: :SingleNonUser, :AllOpposing, :User, :RandomOpposing, :AllNonUsers, :NoTarget, :BothSides, :UserSide, :OppositeOpposing, :OpposingSide, :UserOrPartner, :Partner, :SingleOpposing, :DragonDarts

    You can, of course, add in your own flags here. For instance, if you wanted to make a section of moves for an ability that boosted liquid based moves, you could add a :liquid flag for every liquid move!

     

    Move functions are the bulk of moves. They are defined by a 3 digit hexadecimal number starting with 0x. Moves free up starting at 0x18A, and we'll be using that one here.

    They're defined in Battle_MoveEffects.rb and each are subclasses of the general PokeBattle_Move class. You can override every function that PokeBattle_Move calls for your own needs. Move functions must use the respective 3 digit hexadecimal number for its class.

     

    We'll be making a move named Photon Slash. It will go off the highest attack and have a chance to lower defense. It'll be defined here:

    Spoiler
    :PHOTONSLASH => {
    	:ID => 833,
    	:name => "Photon Slash",
    	:function => 0x18A,
    	:type => :LIGHT,
    	:category => :physical,
    	:basedamage => 70,
    	:accuracy => 100,
    	:maxpp => 10,
    	:effect => 20,
    	:target => :SingleNonUser,
    	:desc => "The target is struck with a condensed beam of light. May lower defense. Uses higher attack stat."
    },

     

    In addition, the class we'll need will be defined as such, copy and pasting code from Photon Geyser and Tail Whip:

    Spoiler
    ################################################################################
    # Photon Slash
    ################################################################################
    class PokeBattle_Move_18A < PokeBattle_Move
      def pbEffect(attacker,opponent,hitnum=0,alltargets=nil,showanimation=true)
        return super(attacker,opponent,hitnum,alltargets,showanimation) if @basedamage>0
        return -1 if !opponent.pbCanReduceStatStage?(PBStats::DEFENSE,true)
        pbShowAnimation(@move,attacker,opponent,hitnum,alltargets,showanimation)
        ret=opponent.pbReduceStat(PBStats::DEFENSE,1,abilitymessage:false, statdropper: attacker)
        return ret ? 0 : -1
      end
    
      def pbAdditionalEffect(attacker,opponent)
        if opponent.pbCanReduceStatStage?(PBStats::DEFENSE,false)
          opponent.pbReduceStat(PBStats::DEFENSE,1,abilitymessage:false, statdropper: attacker)
        end
        return true
      end
      
      #Moldbreaking handled elsewhere
      def pbIsPhysical?(type=@type)
        attacker = @user
        stagemul=[2,2,2,2,2,2,2,3,4,5,6,7,8]
        stagediv=[8,7,6,5,4,3,2,2,2,2,2,2,2]
        # Physical Stuff
        storedatk = attacker.attack
        atkstage=6
        atkmult = 1.0
        if attacker.class == PokeBattle_Battler
          atkstage=attacker.stages[PBStats::ATTACK]+6
          atkmult *= 1.5 if attacker.hasWorkingItem(:CHOICEBAND)
          atkmult *= 1.5 if attacker.ability == :HUSTLE
          atkmult *= 1.5 if attacker.ability == :TOXICBOOST && (attacker.status== :POISON || @battle.FE == :CORROSIVE || @battle.FE == :CORROSIVEMIST || @battle.FE == :WASTELAND || @battle.FE == :MURKWATERSURFACE)
          atkmult *= 1.5 if attacker.ability == :GUTS && !attacker.status.nil?
          atkmult *= 0.5 if attacker.ability == :SLOWSTART && attacker.turncount<5 && !@battle.FE == :DEEPEARTH
          atkmult *= 2 if (attacker.ability == :PUREPOWER && @battle.FE != :PSYTERRAIN) || attacker.ability == :HUGEPOWER
          atkmult *= 2 if attacker.hasWorkingItem(:THICKCLUB) && ((attacker.pokemon.species == :CUBONE) || (attacker.pokemon.species == :MAROWAK))
          atkmult *= 0.5 if attacker.status== :BURN && !(attacker.ability == :GUTS && !attacker.status.nil?)
        end
        storedatk*=((stagemul[atkstage]/stagediv[atkstage])*atkmult)
        # Special Stuff
        storedspatk = attacker.spatk
        spatkstage=6
        spatkmult=1.0
        if attacker.class == PokeBattle_Battler
          spatkstage=attacker.stages[PBStats::SPATK]+6
          spatkmult *= 1.5 if attacker.hasWorkingItem(:CHOICESPECS)
          spatkmult *= 2 if attacker.hasWorkingItem(:DEEPSEATOOTH) && (attacker.pokemon.species == :CLAMPERL)
          spatkmult *= 2 if attacker.hasWorkingItem(:LIGHTBALL) && (attacker.pokemon.species == :PIKACHU)
          spatkmult *= 1.5 if attacker.ability == :FLAREBOOST && (attacker.status== :BURN || @battle.FE == :BURNING || @battle.FE == :VOLCANIC || @battle.FE == :INFERNAL) &&  @battle.FE != :FROZENDIMENSION
          spatkmult *= 1.5 if attacker.ability == :MINUS && (attacker.pbPartner.ability == :PLUS || @battle.FE == :SHORTCIRCUIT || (Rejuv && @battle.FE == :ELECTERRAIN)) || @battle.state.effects[:ELECTERRAIN] > 0
          spatkmult *= 1.5 if attacker.ability == :PLUS && (attacker.pbPartner.ability == :MINUS || @battle.FE == :SHORTCIRCUIT || (Rejuv && @battle.FE == :ELECTERRAIN)) || @battle.state.effects[:ELECTERRAIN] > 0
          spatkmult *= 1.5 if attacker.ability == :SOLARPOWER && (@battle.pbWeather== :SUNNYDAY && !attacker.hasWorkingItem(:UTILITYUMBRELLA)) &&  @battle.FE != :FROZENDIMENSION
          spatkmult *= 1.3 if attacker.pbPartner.ability == :BATTERY
          spatkmult *= 2 if attacker.ability == :PUREPOWER && @battle.FE == :PSYTERRAIN
        end
        storedspatk*=((stagemul[spatkstage]/stagediv[spatkstage])*spatkmult)
        storedspatk= attacker.getSpecialStat if @battle.FE == :GLITCH && attacker.class == PokeBattle_Battler
        # Final selection
        if storedatk>storedspatk
          return true
        else
          return false
        end
      end
    
      def pbIsSpecial?(type=@type)
        return !pbIsPhysical?(type)
      end
    end

     

     

    After that, you can run compileMoves and see your move in game!

    For a quick method of teaching it to a Pokemon, open F6 and type in $Trainer.party[0].pbLearnMove(:PHOTONSLASH) to teach it to the first Pokemon in your party, forgetting the first move it has.

     

    Adding a Z-Move

    Z-Moves are quite simple to add with our new setup. The main bulk is editing various files which I will detail.

    First, we need to create another new move for our Z-Move. You really only need to copy an existing Z-Move and change values to match your intentions. I've gone ahead and done that for you:

    Spoiler
    :BLINDINGLIGHT => {
    	:name => "Blinding Light",
    	:function => 0x000,
    	:type => :LIGHT,
    	:category => :physical,
    	:basedamage => 100,
    	:accuracy => 0,
    	:maxpp => 0,
    	:target => :SingleNonUser,
    	:kingrock => true,
    	:zmove => true,
    	:desc => "The user absorbs the light around it and unleashes it in a wave towards the target. The power varies, depending on the original move."
    },

    Add that to movetext.rb and compile. Then we can move on to the tedious part.

    If you've added a new type when doing this, you may want add a new form to Silvally or Arceus. Those will be found in Battle_MoveEffects.rb and Battler.rb/Pokemon.rb. They modify the Judgment/Multi Attack and Arceus/Silvally forms respectively. I'll get into adding forms later, however I won't be detailing the animation editor, which can be found in the bottom of the debug menu. I simply have never touched it and therefore will not attempt to explain something I don't know.

    Back to Z-Moves. The first file we're going to want to check out is ItemEffects.rb. You'll find a line of code in there that says:

    ItemHandlers::UseOnPokemon.copy(:NORMALIUMZ, :FLYINIUMZ, :GROUNDIUMZ, :BUGINIUMZ, :STEELIUMZ,
      :WATERIUMZ, :ELECTRIUMZ, :ICIUMZ, :DARKINIUMZ, :FIGHTINIUMZ, :POISONIUMZ, :ROCKIUMZ, :GHOSTIUMZ,
      :FIRIUMZ, :GRASSIUMZ, :PSYCHIUMZ, :DRAGONIUMZ, :FAIRIUMZ)

    We'll simply add :LIGHTINIUMZ to the end of this list for the name of our item, which we'll add later. 

     

    The next place to look is in the file PBStuff.rb. This file is an amalgam of lists used in various places throughout the files. The hashes we're concerned with right now are TYPETOZCRYSTAL, MOVETOZCRYSTAL, and CRYSTALTOZMOVE. We can ignore MOVETOZCRYSTAL as we are making a type based Z-Move and not a Pokemon specific one, but the same process as below applies, just making sure to follow the formatting shown in the hash. To add our Z-Move, we'll need to add the following two lines to TYPETOZCRYSTAL and CRYSTALTOZMOVE respectively.

    :LIGHT => :LIGHTINIUMZ
    :LIGHTINIUMZ => :BLINDINGLIGHT

    I cannot stress this enough but do not forgot to use commas. Commas need to separate hash and array entries, and the code will not run if you forget commas. You'll see this constantly if you're doing big edits at once and forget commas here and there (trust me, everyone on the dev team is guilty of this).

     

    Now that we've done this, we can move on to items.

    • Like 2
  9. Adding a Type

    The first thing we'll do is probably the easiest. We'll add a new type to the game. 

    We'll call it the Light type, to match our new Pokemon later on down the line.

     

    A type is defined as such:

    Spoiler
    :DARK => {						# Type identifier
    	:name => "Dark",				# Display name
    	:weaknesses => [:FIGHTING,:BUG,:FAIRY,:SHADOW],	# Takes super effective damage from these types
    	:resistances => [:GHOST,:DARK],			# Takes not very effective damage from these types
    	:immunities => [:PSYCHIC],			# Takes zero damage from these types
    	:specialtype => true				# Defines whether this type is a special or physical in Glitch fields.
    },

     

    To make ours, we need to open the typetext.rb file, and add our new type at the end. I've gone and typed it out for you.

    Spoiler
    :LIGHT => {
    	:name => "Light",
    	:weaknesses => [:DARK,:NORMAL],
    	:resistances => [:BUG,:ELECTRIC,:LIGHT],
    	:immunities => [:FIRE],
    	:specialtype => true
    }

     

    After that, we'll need a few different images. I've gone and made them for you already as detailed at the top of post.

    From there, we can start to compile.

    1. Hit F6 and type compileTypes
    2. Hit enter and fully close the game

    You've set up the type! We'll add a new move next.

    • Like 1
  10. Converting PBS Files

    The Rebornverse games no longer use the PBS files from Essentials, but rather a new data format we've elected to call Data Object Hashes, or DOH. It's a rather straightforward name, the objects are stored in cache as subclasses of the DataObject class, and they are stored as hash files. I have done my best to ensure that the conversion is as simple as possible, but there are still a few things that need to be done by hand unfortunately. 

    This post is strictly for content modders not wishing to lose all of their progress, despite how streamlined modding is now. If this does not apply to you, carry on.

     

    Before I detail the steps, here are the things that won't be converted automatically:

    • Types. There's hardly any and they're very easy to set up.
    • Abilities. There's a lot, and when most are adding Gen 8/PLA abilities, we already have them in the game. They're also even easier to set up than types.
    • Items. The formatting is far too different and the amount of flags we have added for items doesn't convert directly from the PBS files.
    • Moves. Same reason for items and abilities.
    • Forms. Unfortunately, literally impossible. If you wanted to manually convert them to Reborn E19.16 format then you could *possibly* convert them to current DOH format, but that's way more effort than just making a new form.

     

    Conversion Process

    To start things off, here's the file for the converter. To use it, place the file in the Data/Mods folder.

    1. Open the game
    2. Hit F6 and type convertPBS
    3. This will open a small little menu where you can select the things to convert being; Pokemon, Trainer Types/Teams, Encounters, Map Connections, and Metadata. I strongly recommend only using Pokemon conversion, but I know those with lots of encounter changes and trainer changes would be left out.

    Pokemon should largely be unaffected as they merge the PBS into the existing DOH. Trainers do not have their defeat lines included from conversion, which means those need to be manually added. Encounters should be fine to use provided map data has not changed (looking at you, Rejuv). The same applies for Connections and Metadata. Connections should most likely be ignored for most modders and was really only because it was super easily convertible. 

     

    And that's that for converting. Anything not mentioned will be explained later in the posts.

    • Like 2
  11. An Overview

    Pokemon Rejuvenation and Desolation (and soon Reborn) use an almost completely overhauled version of Essentials which makes regular modding as most of you in the community have known it irrelevant, especially in comparison to old versions of these games. This tutorial aims to cover almost all bases; Pokemon, items, moves, abilities, town map (rejuv), trainers, trainer types, bosses, and anything else I can think of.

     

    NOTES:

    This tutorial assumes you have a basic understanding of coding. This includes general syntax and knowing how to read error messages (VERY IMPORTANT AND VERY SIMPLE).

    This tutorial is for Rejuvenation V13.5+, Desolation EP6+, and Reborn E19.17+

    This tutorial is specifically built off Rejuvenation V13.5. Some graphics used later on may be entirely irrelevant to Desolation and Reborn and may require their own different graphics due to the custom UI.

    This tutorial is based on Windows operating systems. I do not claim to have knowledge of how MacOS or Linux devices operate and do not guarantee these steps will work exactly as listed.

    Do not use any online functions of any games while modding. 

    I will not be doing anything inside of RPG Maker XP. Using that software is the easiest part provided you *own* it in the first place.

    I will not be covering fields. They are very clearly outlined as to how they work in each game's respective fieldtxt.rb file, and frankly have too much to explain implementation for them all.

     

    Getting Started

    So! You want to mod, huh? Cool. Here are a few steps to get you started.

    Download a text editor other than Notepad. I personally recommend Visual Studio Code, as it is what I will be using.

    You'll also want a clean copy of any of the games, meaning nothing has been changed and no mods are added.

    Before we get started on doing anything, I'll walk you through setting up your workspace.

     

    Step 1

    First, we're going to set up the console, which means yes, the horrid "D"-word. The console window will not let you interact with the game, instead it prints out additional information and lets you utilize a separate print feature that does not cause pop-ups. The main reason for this is to get access to the F6 functionality, which lets us directly run scripts in-game.

    Steps:

    Spoiler

    1. Right click Game.exe

    2. Click Create Shortcut

    3. Right click the shortcut that was just made. On a clean install it should be labeled Game.exe - Shortcut

    4. There will be a text field labeled Target. Select that text field, and go to the end of the text there. Type debug at the end like so:

        image.png.222c189d0ddce0430bbd93bc2d545d96.png

    5. Click Apply and then close the window.

    You can now launch the game from the shortcut and it will show with a second screen that we call the console.

    image.png.eef794b985583eecb262877f0729bd82.png

     

    Step 2

    Lastly, we will set up our workspace. Editors such as Notepad++ should have similar capabilities, but for the purposes of this tutorial, I will be using Visual Studio Code, as linked above.

    Spoiler

    1. Open Visual Studio Code. Press File > Open Folder. Navigate to the respective game's root folder and select the Scripts folder inside.

    2. On a first launch of VSC, it will prompt you to install a plugin for the language being used. It should automatically find the correct plugin, but you're simply looking for one named Ruby. Here's the link: https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby

    3. There should also be another pop-up prompting you to open a workspace. You'll want to go ahead and allow that as well. It should be labeled Perry Script workfolder.code-workspace. This will let you edit the PBS files from VSC as well. Ignore the rest of this step if this is the case.

    4. If it is not included, we need to create a workspace.

    1. Click File > Add Folder to Workspace and select the PBS folder
    2. Click File > Save Workspace As...

     

     

    And that's that! You're ready to start modding!

    But before we do that, here's a link to every new file being used for this tutorial if you'd like to follow along. I will not be providing any pre-compiled code. To use these graphics, drag the extract folders into the root directory of your game (the one with Game.exe!)

    Download

    • Like 1
  12. On 8/18/2023 at 7:34 PM, BeautifulSinner said:

    Hi I have been trying to add a mon into reatomized and i keep getting this error pop up Everytime I try to debug the Mon into the game 

     

    IMG_4661.jpeg

    It's difficult to tell what exactly is going here. I very recommend not having your game stored in your computer's Temp directory in the first place. From the looks of it, something broke during compilation.

  13. On 9/5/2023 at 12:02 PM, JacobBasque said:

    I've been trying to add hydrabond from all gen reborn to my custom mega hydreigon  but when I go to click an attack I get this message I checked where it says the error is but there doesn't seem to be any error only in game

    Screenshot (18).png

    You'll need to actually define the move inside the effects code. You didn't properly get all the code from All Gen. You'll be easily able to find everything by just searching through the code for PBEffects::HydraBond

    • Thanks 1
  14. On 8/8/2023 at 2:39 AM, suzume said:

    Thank you so much for the tutorial! Really appreciate the time and effort you took to make this! I'm super new to all of this and it's been so helpful and educational! If you don't mind, I was wondering if you teach us how to add custom regional forms to the sprite sheet(especially if there's already another form like with megas) please? I tried searching for tutorials on how to do it but I could only find them for previous verions of the game from back when the sprites were still seperate.  

    It's super easy. The file is arranged so that each Pokemon occupies a 192x192 square, with the backsprite being below it and the shinies being to the right. While it does require some know-how of working with art programs, and I recommend paint.NET or Piskel, all you're really doing is hitting the program-equivalent "Canvas Size..." button and increasing that value by 192 then placing in your sprites.

     

    On the topic of, say, Galarian Slowpoke and Slowbro, our standard has largely been to just shift the Mega Form down 384 pixels and place the Galarian form between them, so as to prevent issues arising with evolutions pulling the wrong graphic. This does require the addition of changing Mega Slowpoke's form value to 2 instead of 1, but there should be a self explanatory field in the file for forms. 

    While you don't particularly need to shift around existing forms, it does make the sprite sheet look like it has less "empty space," even though it's not much of a difference either way.

     

    Sometimes, however, you'll have a sprite that exceeds the bounds of the 192x192 square. As of current Reborn E19, I believe these cases are handled specifically in the various bitmap methods (very easily findable looking for mentions of Exeggutor, Necrozma, Guzzlord, etc). You'll need to add your own exception to that list as well and properly label the sprite in the files in 4 separate images when applicable (For a Bulbasaur: "001_1.png", "001b_1.png", "001s_1.png", "001sb_1.png"). You'll also need a similar extra file when dealing with gender differences as well, simply adding an "_f" before the file extension. While thinking about it, I'm not exactly sure how a sprite that is too big would be handled with gender differences. Oh well.

    • Like 1
    • Thanks 1
  15. Afterword

    Very useful and very powerful commands I have not explained are the puts and print commands. Puts will print out messages to the console you have opened in the background. Print will pop up and pause the game with a message window. If anything you code ever doesn't work, litter these all across your code to see what went wrong. You can use them to show variables at certain times in the code or just to label where in the code you are so you know what's not getting run. I know I use them literally all the time. I know the other devs that work with us do too. There should still be some littered about the code. 

     

    If you understood anything that was said throughout this whole thing, congrats! You've got it in you to make some really freakin cool mods. If not, don't sweat it! Maybe coding isn't for you. Maybe you're an artist. Maybe you're the ideas person! Maybe you just need to read this through one last time to really digest it. Ctrl + Shift + F is one of your best friends in VSC.

     

    Tutorials like these were what got me into Minecraft modding. Applying those skills towards Rejuvenation got me into making my first mod, the original Randomizer. That got me to the Challenge Pack (what a mess it was), and then on to the dev team for the Rebornian games. Now I'm creating a guide for you all. What I've shown you is by no means the limit. Look at Moto's mods. Look at my other mods. Look at the SWM Modular Modpacks. Look at AllGen. The possibilities are countless. It just takes time to understand what you can do. Please don't get too frustrated at not being able to do something. Calmly think it through. Brainstorm what you want to do, then try to find places in the code where you think you accomplish it. Copy pasting is your friend.

     

    It's back to the dungeon for me though, I have other projects to work on.

     

    Happy modding and lots of love~

    Haru~

    • Like 5
  16. Forms

    Forms are a complete mess and I apologize to any modders out there who deal with them. As the one who rewrote them for Desolation, I feel your pain. 

    Sob story aside, they are quite easy to implement! The file we need is MultipleForms.rb.

     

    While I don't have an example for this one, I'll more accurately go into how they work.

    First, there's a small array at the top called FormCopy. This array contains smaller arrays of [Base, Clone] to save repetition. It'll take anything listed in the Base and copy it over to the Clone.

    Second, the actual meat of forms.

    Rather than array, this uses a hash and symbols, something the current Reborn is almost switched over to. Ruby was built to use them, so we are.

    Each entry is called a key, and they are using the ID number of each Pokemon listed. Each key stores another value, in this case being a hash with different keys inside of it. These new level of keys are: :FormName, :OnCreation, :MegaForm, :PulseForm, :DefaultForm, :UltraForm, and the string of any form name to pull data from.

    • :FormName contains keys, corresponding to form number, which return a form name
    • :OnCreation is a proc{} block that is used when generating encounters to check what form it should generate. Examples include Unown generating randomly and Rattata generating Alolan/Kantonian based on the map.
    • :MegaForm, :PulseForm, :DefaultForm, :UltraForm all correspond to their namesake form and return the specific form ID. Exclusions are Mewtwo and Charizard, who have 2 separate forms.
    • Each form name has its own hash tied to it, with keys overriding the base Pokemon's traits
      • Dex Entry, Type 1, Type 2, Base Stats, Ability, Movelist, Egg Moves, Height, Weight, Evolution, Wild Held Items, Catch Rate, and EV Yield

    There is even further room for customization if you want to put the effort in, but I do not recommend it.

     

    And that's everything directly related to Pokemon covered! 

    You did it! Woohoo!

    • Like 3
  17. Modifying Encounters

    These explanations will start to get shorter as there is less and less to cover. 

    In PBS/encounters.txt, there exists a section for every map with valid encounters. Unfortunately, there is no way to modify what maps have encounters and what tiles are encounter tiles without the use of RPG Maker XP. I will never advocate for buying this unfortunate piece of software, but the things talented people can do will never cease to amaze me.

    Back to encounters, they are very simply formatted.

    1. Map ID
    2. Land Encounter Rate, Cave Encounter Rate, Water Encounter Rate. This line is optional, and defaults to 25,10,10. These are divided by 180 for encounter rate.
    3. Encounter Type
      1. List of Pokemon, Min Level, Max Level, matching to the amount of encounters defined in PokemonEncounters.rb

    The valid encounter types are:

    Spoiler

    Land

    Cave (Cannot exist with any Land encounters or Bug Contest

    Water

    RockSmash

    OldRod

    GoodRod

    SuperRod
    HeadbuttLow
    HeadbuttHigh
    LandMorning
    LandDay
    LandNight
    BugContest

     

    While you can't add encounter types without RMXP, you CAN edit the available slots you can have. By default, you can only have slots as listed by the array EnctypeChance. You can modify these entries to allow for more than the given amount. Be warned, that you may encounter issues on places that don't have the new number you set them to, as each slot must be filled. Each sub array of EnctypeChance is based in percentages.

    EnctypeDensities stores the default values for encounter rate. You can ignore this. And I'm honestly not too sure what EnctypeCompileDens is for if I'm being honest. These are all fairly old as far as I'm aware and there's little need to touch any of it.

     

    The same process as before applies to changing encounters. Replace a Pokemon, change their possible levels, compile, and test!

    • Like 3
  18. Adding Items

    We'll add 2 different items here. A new TM, and a new battle item. 

    Items are defined in PBS/items.txt and TM compatibility is stored in PBS/tm.txt. We'll cover tm.txt later, so let's focus on items.txt for now.

     

    The format for items is comprised of:

    1. ID
    2. Internal Name
    3. Display Name
    4. Item Pocket (Items, Medicine, Poke Balls, TMs, Berries, Crystals, Battle Items, Key Items, being represented by a number 0 through 7 in order)
    5. Item Price
    6. Item Description
    7. Item Use From Bag
      Spoiler

      0 - No use

      1 - One time use with party screen (Potions)

      2 - One time use (Repel, Escape Rope)

      3 - TMs

      4 - TMX (HMs)

      5 - Multi-use party screen (Legendary items, Flutes)

       

    8. Item Use In Battle
      Spoiler

      0 - No use

      1 - Single use (Potions, Elixirs)

      2 - Single use without target (X Items, PokeBalls, PokeDoll)

      3 - Flutes

       

    9. Item Type
      Spoiler

      0 - Other

      1 - Mail (Unused)

      2 - Mail

      3 - Snag Ball (Unused)

      4 - Poke Ball

      5 - Berry

      6 - Key Item

      7 - Z Crystal (bag item)

      8 - Z Crystal (held item)

       

    10. TM Move if applicable

    For a TM, let's create a TM for Megahorn. To do this, we need to first search through the list of items and find the last created TM. In our case, that would be TM101. Then, we head down to the end of and get our next ID, giving us:

    874,TM101,TM101,4,7500,"Using a tough and impressive horn, the user rams into the target with no letup.",3,0,0,MEGAHORN

     

    After that, we need to head to PBS/tm.txt. There, we can use the format shown to add the compatibility.

    [INTERNALNAME]
    POKEMON,POKEMON,...

     

    We'll then compile and have a new working TM!

    Spoiler

    image.png

     

    Now, for our battle item. This item will reset all negative stat changes. Seems simple enough, no? 

    First, our icon:

    item875.png.ccf6b0456e07c9bce8f795c5fdcd6bc3.png

    Next, we'll go create an entry in the text file for our item:

    875,XRESET,X Reset,7,500,"Removes all negative stat changes.",0,2,0

    Then we can compile, and the item exists. But we still need to code its function. Here comes the doozy of a file named PokemonItemEffects.rb.

    In here we have our ItemHandlers. We're going to want to head down to where it's labeled BattleUseOnBattler, which is where flag 2 of field 8 has all its items.

    To know what to do here requires decent knowledge of each method available to a battler, item, and scene. In short, a battler has every attribute and method listed in PokeBattle_Battler.rb, an item is the item ID, and the scene will let you print messages in battle.

    Our code should look something like this:

    Spoiler
    ItemHandlers::BattleUseOnBattler.add(:XRESET,lambda{|item,battler,scene|
       playername=battler.battle.pbPlayer.name
       itemname=PBItems.getName(item)
       scene.pbDisplay(_INTL("{1} used the {2}.",playername,itemname))
       reducedstats=false
       for i in 1..7
         if battler.stages[i]<0
          battler.stages[i]=0; reducedstats=true
         end
       end
       if reducedstats
         scene.pbDisplay(_INTL("{1}'s negative stats were reset!",battler.name))
         return true
       end
       scene.pbDisplay(_INTL("But it had no effect!"))
       return false
    })

     

    To explain a little further what's going on here:

    1. We access the Trainer name through the battler's battle accessor, through the pbPlayer method, and then accessing the name flag of the Player. Which, if you took a second to look at any other code, is very stupid. This will be fixed in the next game update.
    2. Get the item name 
    3. Print a use message using _INTL. You can mark variables using curly brackets and numbers. {1} means it will pull the first variable enclosed in the given arguments. _INTL is what most display text uses, and runs through a text formatter.
    4. We copy the code from White Herb elsewhere in the code. Essentially, we check every stat that is not HP to see if it has been reduced, if so, we toggle a flag and reset it.
    5. If the flag has been switched on, we confirm use. If not, we deny use.

    Explanation aside, we can now compile for another working item! ItemHandlers are how items are coded functionally. Looking through a few examples like Poke Balls and Potions will help give a better understanding, Certain items, like Poke Balls, utilize shortcuts to account for every type of ball to generalize them. Those Poke Ball catch rates are handled during the battle. Others, such as Evolution Stone items, copy the handler for one item on to every other one of its type.

    Spoiler

    image.png

     

    • Like 3
  19. Adding a Type

    This one's easy. Unfortunately, it's also incredibly broken. You'll need to download this file to make the type compiler work. Our bad.

    Anyway. Light Type. Simple and quick. On brand to a Volbeat line. 

     

    Heading over to PBS/types.txt,we see a few parameters, being:

    • Name
    • InternalName
    • IsSpecialType, which decides if a type is physical or special on Glitch field
    • Weaknesses, which types it is weak to
    • Resistances, which types it resists
    • Immunities, which types it is immune to

    We can pretty much throw anything at it. Here's what I did

    [19]
    Name=Light
    InternalName=LIGHT
    IsSpecialType=true
    Weaknesses=DARK,NORMAL
    Resistances=BUG,ELECTRIC,LIGHT
    Immunities=FIRE

    Additionally, I added Light to Dark's Weakness field to make them weak to each other.

     

    Then we'll go ahead and replace Beatote's Ground typing with Light in PBS/pokemon.txt, and then compile. The last thing we need is an image for the type. I'll provide that, and it needs to replace the one in Graphics/Pictures. You'll need an editor such as paint.NET if you want to do it yourself.

    Spoiler

    image.png.0953b652c78492f11039d8d87db6f400.png

     

    And there's a new type! Probably the easiest thing so far. 

    There are other graphics where a light type might need its own image, such as in the field notes or in battle. Those are in Graphics/Icons and Graphics/Pictures/Battle respectively.

    • Like 3
  20. Evolutions

    Now. I'm sure you've thought Beatote is familiar at this point. It's actually a fake evolution of Volbeat! For our evolution method, we will be having Volbeat need to know Tail Glow and be at least level 30. Let's code that in!

     

    To start, we need to head to PokemonEvolution.rb

    Our first step is to define a new evolution constant. These are what you'll see immediately into opening the file. At the end of that list, you'll want to this add the code. 

    Beatote = 33

    Feel free to make the spaces match.

     

    Next, we'll want to add to the EVONAMES array. Just add a "Beatote" entry right after where it says "Custom7".

     

    Finally, to finish the definition, we need to add to the EVOPARAM array. What each number means is defined right above it. All we want for that is an integer, which is to say another 1. Below is what the two arrays should look like:

    Spoiler
    EVONAMES=["Unknown",
      "Happiness","HappinessDay","HappinessNight","Level","Trade",
      "TradeItem","Item","AttackGreater","AtkDefEqual","DefenseGreater",
      "Silcoon","Cascoon","Ninjask","Shedinja","Beauty",
      "ItemMale","ItemFemale","DayHoldItem","NightHoldItem","HasMove",
      "HasInParty","LevelMale","LevelFemale","Location","TradeSpecies",
      "BadInfluence","Affection","LevelRain","LevelDay","LevelNight","Custom6","Custom7",
      "Beatote"
    ]
    
    # 0 = no parameter
    # 1 = Positive integer
    # 2 = Item internal name
    # 3 = Move internal name
    # 4 = Species internal name
    # 5 = Type internal name
    EVOPARAM=[0,     # Unknown (do not use)
      0,0,0,1,0,     # Happiness, HappinessDay, HappinessNight, Level, Trade
      2,2,1,1,1,     # TradeItem, Item, AttackGreater, AtkDefEqual, DefenseGreater
      1,1,1,1,1,     # Silcoon, Cascoon, Ninjask, Shedinja, Beauty
      2,2,2,2,3,     # ItemMale, ItemFemale, DayHoldItem, NightHoldItem, HasMove
      4,1,1,1,4,     # HasInParty, LevelMale, LevelFemale, Location, TradeSpecies
      1,1,1,1,1,1,1, # Custom 1-7
      1              # Beatote
    ]

     

    Now, to actually implement our evolution method, we need to head down to the method pbMiniCheckEvolution. The method takes in 4 parameters, being the Pokemon object, its evolution method, the parameter defined in PBS/pokemon.txt, and the species it evolves into. 

    Following the structure shown in pbMiniCheckEvolution, we want to do the same for our new one, making sure our Pokemon is above the level and has the required move. That will look like this:

    when PBEvolution::Beatote
    	return poke if pokemon.level >= level && pokemon.knowsMove?(:TAILGLOW)

     

    Lastly, we need to add the evolution method to Volbeat in PBS/pokemon.txt. It's very simple, all that needs to be done is filling out the evolution field in Volbeat's block. Reminder you can push Ctrl + F to search through a file.

    Evolutions=BEATOTE,Beatote,30

     

    After that, you can compile, and the evolution will work.

    Spoiler

    image.png.6b02d986fa9114af16279d7a96413606.png

     

    • Like 3
  21. Adding an Ability

    Next up, abilities.

     

    Abilities, as you'd expect, are defined in PBS/abilities.txt. They're very straightforward on the PBS end of things, only requiring an ID, Internal Name, Display Name, and Description. On the other hand, the entire implementation is code based. 

    To fit in with Beatote's Pokedex entry of preying on Nincada, let's have its ability make its attack increase by 50% against Bug-type Pokemon.

     

    To start, defining its ability in the PBS:

    330,SCAVENGER,Scavenger,"Deal increased damage to Bug-type Pokémon."

     

    Next, we'll give that ability to Beatote.

    HiddenAbility=SCAVENGER

     

    Now we can compile, and Beatote will now have the Scavenger ability!

    Spoiler

    image.png.b806cf28d60f4aadf40bc9d1538c758d.png

     

    And now, we need to implement it!

    There's a lot to do here, so bear with me and try to follow along. We want to head to the file PokeBattle_Move.rb. This file is where all damage calculation takes place, and where the magic mainly happens.

    You'll want to head down to around line 1448, which is after all the field effect code. You'll be looking for a line that says:

    case attacker.ability
    when PBAbilities::GUTS

    In here, we'll want to add a few lines so we end up with:

    case attacker.ability
    when PBAbilities::SCAVENGER
    	atkmult=(atkmult*1.5).round if opponent.hasType?(:BUG)
    when PBAbilities::GUTS

    I'll explain what's going on here.

     

    This is a method called pbCalcDamage. Inside of it, it takes three parameters in addition to an optional hitnum named parameter. While the parameters options and hitnum are inconsequential, attacker and opponent are what we really care about here. Both attacker and opponent will be PokeBattle_Battler objects, found inside PokeBattle_Battler.rb. Any method or attribute in there can be called and utilized for creating a damaging move.

    The method hasType? takes a type and returns if the object has it or not.

     

    pbCalcDamage is split into parts:

    Spoiler
    1. Initialization, including exiting if base damage is 0, pulling base damage from PBS, etc.
    2. Calculate the base damage.
      1. Abilities, such as Sheer Force and Pixilate.
      2. Items, such as gems, plates, and legendary orbs (Griseous Orb, Soul Dew, etc)
      3. More effects conditionally, being Charge, Helping Hand, Mud/Water Sport, Kalos Legend Abilities, Knock Off, and Lunala Z vs Minimize.
      4. Field effect changes.
    3. Calculate the attacker's attack stat comes next, being the Pokemon using the move.
      1. Determine if physical or special.
      2. Adjust for Unaware/Hustle/Power Spot.
      3. More field effects.
      4. Conditional attack modifier abilities (Starters, Swarm).
      5. Attack modifier abilities (Scavenger, Huge Power, Guts, Flash Fire, etc).
      6. Item modifiers, such as Light Ball, Thick Club, Choice items
      7. Thick Fat must be done LAST.
    4. Calculate the corresponding defense stat.
      1. Same shtick applies here. Very repetitive.
    5. Calculate the effective, or actual, damage.
      1. Multihit moves 
      2. Generic field boosts, such as type matching.
      3. Primal Abilities return 0 damage here if nullified by respective weather.
      4. Field transformations, such as Crystal Cave > Dark Crystal Cave or Factory Field
      5. Sun/Rain
      6. Crit calculation
      7. Damage rolls
      8. STAB calculation
      9. Type effectiveness check
      10. Gem message + Burn/Water Bubble
      11. Effective damage mods, such as Screens, Multiscale, Friend Guard, Life Orb, Berries, etc.
    6. Calculate final damage using above methods.

     

    Now your ability functions. But only for the player. The AI does not know what's actually going on with your ability, it simply sees nothing, We need to head to the file "PokeBattle_AI_2.rb".

    This file is a wonder. It's incredibly complicated and I won't bore you trying to teach it. The gist is, you need to find similar functioning abilities and insert your new ability in. If you look at where we inserted Scavenger in the PokeBattle_Move.rb, we should look for spots where those abilities are and copy them, provided we ignore any field-specific effects for them. This will apply similar logic to before. I'll state which methods we'll be modifying. This part doesn't need to be done, but should if you plan on making the AI have a fair chance.

     

    Certain abilities should be more weighted heavily in the first location, a method called getAbilityDisruptScore, which is the score the AI gets for whether or not it should "counter" the ability. We'll place this right near where the code for Huge Power is. The multiplier here is typically the same.

    when PBAbilities::SCAVENGER
    	abilityscore*=1.5 if opponent.hasType?(:BUG)

     

    The next spot is where we calculate ability score for the AI to find the best switch for. It can be found by searching abilityscore in the file. It starts at around line 8035 on clean code.

    Pretty much anywhere after the line case i.ability we will be adding the code:

    when PBAbilities::SCAVENGER
    	abilityscore+=30 if @opponent.hasType?(:BUG)

    The amount to add here is pretty subjective. The general process is 10 for "hey this is better than no ability" or a much higher number for "hey this is a really freaking good idea do this."

    However much you want to add for your own abilities is up to you.

     

    The final spot where it's required is much further down labeled with a comment tag

    ############ ATTACKER ABILITY CHECKS ############

     

    You can search for this to find it. We'll be adding this line into the code there. It can be anywhere after Technician but before Type Changing Abilities. Typically group like changes together.

    #Scavenger
    elsif attacker.ability == PBAbilities::SCAVENGER
    	if opponent.hasType?(:BUG)
    		atk=(atk*1.5).round
    	end

     

    Congrats! You've taken your first real step into full content mods with this! There's still a whole lot going on here behind the scenes, but I'm not going to explain it solely based on the fact it would take way too long to explain everything. I've explained the important stuff, much of it has labels, and much of it is very self-explanatory thanks to our wonderful developers (humblebrag). Let's hop into the next topic.

    • Like 3
  22. Adding a Move

    Probably the next big thing, moves. 

     

    Moves are defined in PBS/moves.txt. They're a lot more complicated to set up, but quite fun to make. Let's break down the structure before we add any.

    1. The first field is the ID. They are typically in ascending order, but sometimes have gaps.
    2. The internal name is next. This is what you'll be using in the scripts and PBS files.
    3. The next field is the display name.
    4. The next field is the move function. I will explain this later.
    5. Next is the Base Power. 0 means no base power. 1 means custom power. Anything else is fair game.
    6. Typing. Any available type from PBS/types.txt
    7. Category. Physical/Special/Status. If defined as status, the base power MUST be zero. If defined as Physical/Special, the base power MUST be non zero.
    8. Accuracy. Number from 0 to 100. 0 never misses.
    9. Max PP. Any number. This number is before PP Ups. PP Ups are calculated automatically
    10. Effect chance. Percent chance for a secondary effect to trigger.
    11. Target Selection. Which Pokemon the move can target.
      Spoiler

      00 - Single Pokémon other than the user

      01 - No target (i.e. Counter, Metal Burst, Mirror Coat, Curse)

      02 - Single opposing Pokémon selected at random (i.e. Outrage, Petal Dance, Thrash, Uproar)

      04 - All opposing Pokémon

      08 - All Pokémon other than the user

      10 - User

      20 - Both sides (e.g. Sunny Day, Trick Room)

      40 - User's side (e.g. Light Screen, Mist)

      80 - Opposing side (i.e. Spikes, Toxic Spikes, Stealth Rocks)

      100 - User's partner (i.e. Helping Hand)

      200 - Single Pokémon on user's side (i.e. Acupressure)

      400 - Single opposing Pokémon (i.e. Me First)

      800 - Single opposing Pokémon directly opposite of user

       

    12. Move Priority. Used in determining turn order, values range from -6 to 6.
    13. Flags. By far the stupidest system of doing this but here we are. This includes aspects like sound, contact, high crit rate, etc. It can be any combination of letters a through n
      Spoiler

      a - The move makes physical contact with the target.

      b - The target can use Protect or Detect to protect itself from the move.

      c - The target can use Magic Coat to redirect the effect of the move. Use this flag if the move deals no damage but causes a negative effect on the target. (Flags c and d cannot both be used)

      d - The target can use Snatch to steal the effect of the move. Use this flag for most moves that target the user. (Flags c and d cannot both be used)

      e - The move can be copied by Mirror Move.

      f - The move has a 10% chance of making the opponent flinch if the user is holding a King's Rock/Razor Fang. Use this flag for all damaging moves that don't already have a flinching effect.

      g - If the user is frozen, the move will thaw it out before it is used.

      h - The move has a high critical hit rate.

      i - The move is a biting move (powered up by the ability Strong Jaw).

      j - The move is a punching move (powered up by the ability Iron Fist).

      k - The move is a sound-based move.

      l - The move is a powder-based move (Grass-type Pokémon are immune to them).

      m - The move is a pulse-based move (powered up by the ability Mega Launcher).

      n - The move is a bomb-based move (resisted by the ability Bulletproof).

    14. Description. Move description.

     

    Now that we have these, we can create our own move. For an example, we'll be creating a move for our Beatote named "Bug Strike". It will have a high crit ratio, contact, get affected by protect, be affected by mirror move, flinch with king's rock, and have a chance to paralyze.

    We can define that by:

    772,BUGSTRIKE,Bug Strike,189,70,BUG,Physical,100,10,20,00,0,abef,"The user strikes the target with a tough appendage. Critical hits land more easily."

    But wait! Function 189? What's that?

    This is where the hard part comes in. We need to go to the file PokeBattle_MoveEffects.rb. This is where all of our move functions are defined. To make things simple, we will copy the code from Thunder. In case that file is not labeled with each move (You should definitely do this), you can find the function in PBS/moves.txt and search for it in PokeBattle_MoveEffects.rb.

    At the end, the code should look like this:

    # Bug Strike
    class PokeBattle_Move_189 < PokeBattle_Move
      def pbAdditionalEffect(attacker,opponent)
        return false if !opponent.pbCanParalyze?(false)
        opponent.pbParalyze(attacker)
        @battle.pbDisplay(_INTL("{1} was paralyzed! It may be unable to move!",opponent.pbThis))
        return true
      end
    end

    Since we've defined a chance to proc an additional effect, we need to use the method pbAdditionalEffect. If we were to look at a status move or something like Superpower or Drain Punch, they use pbEffect. Moves like Thunder Fang with two effects require an additional method called pbSecondAdditionalEffect. If you were to want a move to have more than 2 additional effects with separate chances, you'd need to find where each of these methods are called in the game's scripts and add in new methods for that. Alternatively, you can add in a new random roll inside the effect. 

    While you don't need to use pbAdditionalEffect and can just use pbEffect, it's better to stick with conventions and use them as intended.

     

    Finally, to use the move, we need to give it to a Pokemon. We can simply add at the front of our Moves field in the Pokemon data "1,BUGSTRIKE"

    An example of adding the move will be hidden below.

    Spoiler
    Moves=1,BUGSTRIKE,1,FLASH,1,TACKLE,5,DOUBLETEAM,8,CONFUSERAY,12,QUICKATTACK,15,STRUGGLEBUG,19,MOONLIGHT,22,TAILGLOW,26,SIGNALBEAM,29,PROTECT,33,ZENHEADBUTT,36,HELPINGHAND,40,BUGBUZZ,43,PLAYROUGH,47,DOUBLEEDGE,50,INFESTATION

     

    After that, we can compile all!

     

    Many types of effects are found within PokeBattle_MoveEffects.rb, such as Flying Press's multityped aspect, defining moves able to used while asleep, along with a lot more. The only thing that limits what you can do here is your own coding ability, understanding, and the small fact that you can only affect active battlers. 

    • Like 3
  23. Adding a Pokemon

    So. Let's start with the be-all end-all of Pokemon. Themselves.

     

    Creating a Pokemon is quite easy, and by far the most common mod in the Mod Market. Let's break it down.

    Pokemon in their default forms are found in the PBS folder inside pokemon.txt whereas their forms are found within MultipleForms.rb. The methods, things the game uses, that define a Pokemon are found within the file PokeBattle_Pokemon.rb and PokemonMultipleForms.rb.

     

    Creating a New Pokemon

    To start, open up pokemon.txt inside your workspace.

    Next, we'll go ahead and copy the block of code for Bulbasaur:

    Spoiler
    [1]
    Name=Bulbasaur
    InternalName=BULBASAUR
    Type1=GRASS
    Type2=POISON
    BaseStats=45,49,49,45,65,65
    GenderRate=FemaleOneEighth
    GrowthRate=Parabolic
    BaseEXP=64
    EffortPoints=0,0,0,0,1,0
    Rareness=45
    Happiness=70
    Abilities=OVERGROW,CHLOROPHYLL
    Moves=1,TACKLE,3,GROWL,7,LEECHSEED,9,VINEWHIP,13,POISONPOWDER,13,SLEEPPOWDER,15,TAKEDOWN,19,RAZORLEAF,21,SWEETSCENT,25,GROWTH,27,DOUBLEEDGE,31,WORRYSEED,33,SYNTHESIS,37,SEEDBOMB
    EggMoves=AMNESIA,CHARM,CURSE,ENDURE,GIGADRAIN,GRASSWHISTLE,GRASSYTERRAIN,INGRAIN,LEAFSTORM,MAGICALLEAF,NATUREPOWER,PETALDANCE,POWERWHIP,SKULLBASH,SLUDGE
    Compatibility=Monster,Grass
    StepsToHatch=5355
    Height=0.7
    Weight=6.9
    Color=Green
    Habitat=Grassland
    Kind=Seed
    Pokedex=Bulbasaur can be seen napping in bright sunlight. There is a seed on its back. By soaking up the sun's rays, the seed grows progressively larger.
    BattlerPlayerY=28
    BattlerEnemyY=25
    BattlerAltitude=0
    Evolutions=IVYSAUR,Level,16

    Then, you'll want to paste that all the way down at the end of the file, right after Eternatus. 

    "Hey! Wait! Eternatus isn't in the game!" While that is true, its implementation actually is in the game, it just lacks sprites and is impossible to obtain. We decided it was easier to leave them in at the time of creation since Desolation, which was being developed for its latest release, and Rejuvenation, both had plans for Pokemon from the Galar Region. You can delete everything from after to Zeraora to Eternatus if you don't want a massive gap in your Pokedex.

     

    Back to adding a new Pokemon....

    Everything part of that Bulbasaur is what we're going to call a field. Each field is customizable. So, for our new Pokemon, let's use a fakemon called Beatote from the spriter Samson. You can find his old account on PokeCommunity, but almost all sprites have been taken down due to age. I took these straight out of ROM hacks of old that used them. 

     

    The first things you'll need, of course, are a sprite, icon, and cry. I'll provide them for this Pokemon. You can find them here.

    These must be named with their ID, which will be explained below. Take the image with just the number, and move that to Graphics/Battlers. Take the other image and drag that to Graphics/Icons. Finally, take the audio file and drag that to Audio/SE.

    NOTE: If you delete the Galar Pokemon, you MUST rename these files to their new ID.

     

    Secondly, you'll need to start editing the new Pokemon code you pasted.

    1. The first field, [1], should be changed to the next available ID.
    2. The second field, Name, is the display name.
    3. The third field, InternalName, is the name used in the code.
    4. Type1 is the primary typing. It can be any type defined in the code.
    5. Type2 is the secondary typing. 
    6. BaseStats are the Pokemon stats, of the order HP, Attack, Defense, Speed, Special Attack, Special Defense.
    7. GenderRate is what defines the gender ratio. The possible options are AlwaysMale, FemaleOneEighth, Female25Percent, Female50Percent, Female75Percent, FemaleSevenEighths, AlwaysFemale, and Genderless. 
    8. GrowthRate determines how fast the Pokemon levels up. The options are Medium or MediumFast, Erratic, Fluctuating, Parabolic or MediumSlow, Fast, and Slow. You can learn more about growth rates on any wiki website. 
    9. BaseEXP is the amount of EXP earned from defeating a Pokemon. It can be any whole number greater than zero.
    10. EffortPoints is the EV yield granted when defeated. It follows the same order as BaseStats. They can be any whole number greater than zero.
    11. Rareness is the catch rate. It can be any whole number between 0 and 255
    12. Happiness is the base friendship a Pokemon has. This typically is not changed from 70
    13. Abilities are the main abilities a Pokemon can have. They can be 1-2 abilities from any ability defined in PBS/abilities.txt
    14. HiddenAbility is the hidden ability. This feature is not present and simply a possible ability a Pokemon can have.
    15. Moves is the list of moves a Pokemon can learn by level up. They are formatted as a whole number, followed by the name of the move. 
    16. EggMoves is the list of moves a Pokemon can learn through breeding. 
    17. Compatibility is the Pokemon's egg group. The possible egg groups are: Monster Water1 Bug Flying Field Fairy Grass Humanlike Water3 Mineral Amorphous Water2 Ditto Dragon Undiscovered.
    18. StepsToHatch is the amount of steps require to hatch from an egg. Do not use any commas or decimals to indicate thousands, and it must be a whole number.
    19. Height can be any positive number. They use the American system of using decimal points.
    20. Weight can be any positive number. They use the American system of using decimal points.
    21. Color is typically the main color of the Pokemon. It's used solely by the Pokedex. It can be Red, Blue, Yellow, Green, Black, Brown, Purple, Gray, White, or Pink.
    22. Habitat is the cosmetic "location" a Pokemon can be found. This field can be ignored.
    23. Kind is the type listed in the Pokedex. This can be anything. 
    24. Pokedex is the Pokedex entry displayed in the Pokedex itself. This can be anything.
    25. WildItemCommon, WildItemUncommon, and WildItemRare make up the chance of holding an item, being 50%, 5%, and 1% respectively. If all three of these fields exist AND are the same item, the Pokemon will always spawn with that item. It can be any item defined in PBS/items.txt
    26. BattlerPlayerY and BattlerEnemyY can be left the same. They need to be any whole number. These can be adjusted to suit your needs to change the position.
    27. BattlerAltitude determines the height in battle. Should typically be left at 0. Can be any number greater or equal to 0. Shows a shadow if greater than zero.
    28. Evoltuions is what defines how the Pokemon can evolve. Evolutions have 3 parts: Pokemon, Evolution Method, and Evolution Parameter, in that order. A full list of evolution methods and their parameters can be found in PokemonEvolution.rb. We will discuss these later.

    The premade data for Beatote can be found below:

    Spoiler
    [891]
    Name=Beatote
    InternalName=BEATOTE
    Type1=BUG
    Type2=GROUND
    BaseStats=75,85,90,80,50,85
    GenderRate=AlwaysMale
    GrowthRate=Erratic
    BaseEXP=184
    EffortPoints=0,0,2,0,0,0
    Rareness=45
    Happiness=70
    Abilities=ILLUMINATE,SWARM
    HiddenAbility=PRANKSTER
    Moves=1,FLASH,1,TACKLE,5,DOUBLETEAM,8,CONFUSERAY,12,QUICKATTACK,15,STRUGGLEBUG,19,MOONLIGHT,22,TAILGLOW,26,SIGNALBEAM,29,PROTECT,33,ZENHEADBUTT,36,HELPINGHAND,40,BUGBUZZ,43,PLAYROUGH,47,DOUBLEEDGE,50,INFESTATION
    EggMoves=BATONPASS,BUGBUZZ,DIZZYPUNCH,ENCORE,LUNGE,SEISMICTOSS,SILVERWIND,TRICK
    Compatibility=Bug,Humanlike
    StepsToHatch=4080
    Height=1.4
    Weight=42.3
    Color=Yellow
    Kind=Groundfly
    Pokedex=Beatote live underground, taking over the colonies of the Nincada that live in the area by blinding them.
    WildItemUncommon=BRIGHTPOWDER 
    BattlerPlayerY=23
    BattlerEnemyY=19
    BattlerAltitude=0
    Evolutions=

     

    So now we're done, right? Not so fast! Now that we've created a Pokemon, we need to compile. To compile, you want to

    1. Launch the game via the shortcut created earlier.
    2. Press F6 and type pbCompilePokemonData, then press enter.
    3. Alternatively:
      1. Open any save
      2. Pause the game, select Debug
      3. Scroll to "Compile All Data" and select it
    4. After either option, restart the game.

    You'll pretty much want to do this any time you add new things to the game via the PBS.

    Once you relaunch the game, you can give yourself your new Beatote via debug! Either go to the debug menu and hit Add Pokemon, or push F6 and enter the script:

    pbAddPokemon(PBSpecies::BEATOTE,5)
    Spoiler

    image.png.842b7e11f1ab4868a8824af02fb1166d.png

     

    • Like 5
  24. 3 hours ago, SapphireLucario said:

    Messed with this for a bit. It's cool! However, when I tried to leave the minigame, I couldn't, even when using debug to warp me to other maps.

    EDIT: Upon further testing, I *was* able to leave the minigame. Not sure what happened to me that first time I played.

    You can't actually leave mid-minigame. But since it takes literally 2 seconds to place your chips and hold x, you can just quit the game after that.

×
×
  • Create New...