Registrarse

[pokeemerald] Combos de Captura/Batalla V 1.1

Diego Mertens

Dartrix Joven
Hola! Desde hace unos días, he estado desarrollando el sistema de combos de capturas para Pokeemerald, y creo que ya está lo suficientemente completo como para compartirlo con ustedes, contando con las siguientes características:
  • Los IV de los Pokémon aumentan dependiendo de la cadena, siendo que a partir de 10, el nivel de cadena determina los IV de los Pokémon.
  • La probabilidad de encontrarse con un Pokémon shiny aumenta, hasta un máximo de un 0,2%, o una probabilidad de 1 entre 348.
  • La cadena puede completarse capturando o derrotando al Pokémon salvaje. Escapar de un Pokémon que no era el que buscabas no rompe la cadena.
Por hacer:
  • Añadir Pokémon raros a las rutas (que normalmente no aparecen) cuando la cadena suba.
  • Aumentar la probabilidad de que el Pokémon que buscas aparezca cuando la cadena suba.
  • Hacer que Pokémon con menor probabilidad de aparición sean más comunes cuando la cadena suba.
  • Evitar la ruptura de la cadena si se hace un combate contra un entrenador.
Aquí está la commit del código (desgraciadamente no me dejó ponerlo en una nueva branch):
Código (pondré en spoilers los códigos grandes):
Primero, definimos las variables, vayan a "include/constants/vars.h"
Y renombren alguna variable sin usar como las siguientes:
VAR_CHAIN
Y
VAR_SPECIESCHAINED
En "src/battle_setup.c" añadiremos esto debajo de "static const u8 *GetTrainerCantBattleSpeech(void)" :
C++:
extern const u8 ChainNumber[];
extern const u8 AddChain[];
Luego, reemplazaremos toda la función "static void CB2_EndWildBattle(void)" con esto:
C++:
static void CB2_EndWildBattle(void)
{
    u16 species;
    u16 ptr;
    u8 nickname[POKEMON_NAME_LENGTH + 1];
    u16 lastPokemonFound;
    species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES);
    CpuFill16(0, (void*)(BG_PLTT), BG_PLTT_SIZE);
    ResetOamRange(0, 128);
    if (IsPlayerDefeated(gBattleOutcome) == TRUE && !InBattlePyramid() && !InBattlePike())
    {
        SetMainCallback2(CB2_WhiteOut);
    }
    else
    {
        if ((gBattleOutcome != B_OUTCOME_WON) && (gBattleOutcome != B_OUTCOME_CAUGHT))
        {
            if (species == VarGet(VAR_SPECIESCHAINED) && VarGet(VAR_CHAIN) >= 1)
            {
                VarSet(VAR_CHAIN,0);
                VarSet(VAR_SPECIESCHAINED,0);
            }
            else if ((species != VarGet(VAR_SPECIESCHAINED)) && (VarGet(VAR_CHAIN) >= 1))
                species = VarGet(VAR_SPECIESCHAINED);
        }
        else if ((gBattleOutcome == B_OUTCOME_WON) || (gBattleOutcome == B_OUTCOME_CAUGHT))
        {
            if (VarGet(VAR_CHAIN) == 0)
            {
                VarSet(VAR_SPECIESCHAINED,species);
                ScriptContext1_SetupScript(AddChain);
            }
            else if ((species == VarGet(VAR_SPECIESCHAINED)) && VarGet(VAR_CHAIN) >=30)
                VarSet(VAR_CHAIN,30);
            else if ((species == VarGet(VAR_SPECIESCHAINED)) && VarGet(VAR_CHAIN) >=3)
            {
                GetSpeciesName(gStringVar2 ,VarGet(VAR_SPECIESCHAINED));
                ScriptContext1_SetupScript(ChainNumber);
            }
            else if ((species == VarGet(VAR_SPECIESCHAINED)) && (VarGet(VAR_CHAIN) ==2 || VarGet(VAR_CHAIN) ==1))
                ScriptContext1_SetupScript(AddChain);
            else if ((species != VarGet(VAR_SPECIESCHAINED)) && (VarGet(VAR_CHAIN) != 0))
                VarSet(VAR_CHAIN,0);
                VarSet(VAR_SPECIESCHAINED,species);
        }
        SetMainCallback2(CB2_ReturnToField);
        gFieldCallback = sub_80AF6F0;
    }
}
Cuando hagamos eso, buscamos la función "bool8 IsShinyOtIdPersonality(u32 otId, u32 personality)" en el archivo "src/pokemon.c" y reemplazamos la línea que dice "if (shinyValue < SHINY_ODDS)" con esto:
C++:
if (shinyValue < (SHINY_ODDS + (VarGet(VAR_CHAIN))*6))
Al terminar, en el mismo archivo buscamos "void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId)" y reemplazaremos la definición de los IV con esto:
C++:
        if (VarGet(VAR_CHAIN) >=10)
        {
            u32 iv;
            iv = VarGet(VAR_CHAIN);
            SetBoxMonData(boxMon, MON_DATA_HP_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_ATK_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_DEF_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_SPEED_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv);
        }
        else if (VarGet(VAR_CHAIN) ==30)
        {
            u32 iv;
            iv = 31;
            SetBoxMonData(boxMon, MON_DATA_HP_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_ATK_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_DEF_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_SPEED_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &iv);
            SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv);
        }
        else
        {
            u32 iv;
            value = Random();

            iv = value & 0x1F;
            SetBoxMonData(boxMon, MON_DATA_HP_IV, &iv);
            iv = (value & 0x3E0) >> 5;
            SetBoxMonData(boxMon, MON_DATA_ATK_IV, &iv);
            iv = (value & 0x7C00) >> 10;
            SetBoxMonData(boxMon, MON_DATA_DEF_IV, &iv);

            value = Random();
 
            iv = value & 0x1F;
            SetBoxMonData(boxMon, MON_DATA_SPEED_IV, &iv);
            iv = (value & 0x3E0) >> 5;
            SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &iv);
            iv = (value & 0x7C00) >> 10;
            SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv);
        }

Después, nos vamos a "data/scripts/" y creamos un archivo llamado "chain.inc", y pegamos el siguiente código dentro:
C++:
ChainNumber::
    addvar VAR_CHAIN, 1
    buffernumberstring 0, VAR_CHAIN
    msgbox TextoCool, 2
    end
 
TextoCool::
    .string "Cadena: {STR_VAR_1}, de {STR_VAR_2}.$"
 
AddChain::
    addvar VAR_CHAIN, 1
    end
Luego, debemos ir a "src/overworld.c", y en la función "void CB2_WhiteOut(void)", agregamos estas dos líneas al final de la misma:
C++:
        VarSet(VAR_CHAIN,0);
        VarSet(VAR_SPECIESCHAINED,0);
Y debemos definir el archivo que acabamos de crear en "data/event_scripts.s", por lo que entramos y al final, añadimos esto:
Código:
    .include "data/scripts/chain.inc"

Y con eso, lo tenemos todo listo, cada vez que derrotemos 3 Pokémon salvajes iguales seguidos, aparecerá un mensaje luego del combate que dice el número de la cadena y el Pokémon que estamos buscando, aumentando sus IV y sus probabilidades de ser shiny mientras aumenta la cadena.
 
Última edición:

Jaizu

Usuario mítico
Me gusta mucho el sistema porque es extremadamente útil y el código es considerablemente corto, así que los errores deberían ser mínimos, buen trabajo.
Como única pega, diría que lo suyo sería subir las modificaciones a una branch de pokeemerald para ver los cambios más claramente.
 

~Criisss

Usuario mítico
Si hay algo que me gustó mucho de Let's go Pikachu/Eevee fue el sistema de cadenas para la caza de shinies. ¡Es una excelente idea replicarlo en pokeemerald!
Estoy de acuerdo con lo que dice Jaizu. Cuando consideres que está terminado, lo ideal sería que esté solo esto en un branch aparte para que cualquiera lo pueda importar de manera rápida y facil.

¡Gran aporte!
 

H.B.P

Emperador Kaktiácero
Miembro de honor
En sí no me gusta que se den tantas facilidades, como eso de que la cadena no se rompa si sale otro Pokémon y lo de aumentar la probabilidad de que salga shiny.

No obstante, hablamos de decomp, así que se puede modificar sin problemas.

Un aporte genial, ¡muchas gracias!
 

Diego Mertens

Dartrix Joven
En sí no me gusta que se den tantas facilidades, como eso de que la cadena no se rompa si sale otro Pokémon y lo de aumentar la probabilidad de que salga shiny.

No obstante, hablamos de decomp, así que se puede modificar sin problemas.

Un aporte genial, ¡muchas gracias!
Eso está hecho porque los Pokémon que podemos estar queriendo encadenar podrían ser relativamente raros, o la ruta bastante diversa, y no sería un mecánica útil al ser así. Imaginate que estás encadenando un Makuhita en la Granite Cave y te sale un Geodude, rompiendo la cadena. Seguro te refieres a que sería mejor como con el Pokéradar, pero en realidad no, porque con el radar tienes un relativo control de la cadena si sabes lo que haces. Además, así es en Let's Go! xd
Pero sí, es bastante fácil modificarlo, sobretodo porque con eliminar un "if" o cambiar unas líneas, puedes tenerlo customizado.
 

Diego Mertens

Dartrix Joven
Lo he subido a una branch de Github: https://github.com/Jaizu/pokeemerald/tree/combos-captura-batalla


He encontrado dos bugs:
- La cadena se rompe si capturas al Pokémon
- Si el pokémon salvaje te debilita la cadena no se rompe, deberías resetear las vars en la función del whiteout.
Sí, lo de capturar al Pokémon ya lo he resuelto (aún tengo que recordar que esto no es RGSS y los condicionales funcionan distinto), y lo otro no me había dado cuenta, no se me pasó por la cabeza la posibilidad de que pasara, ¡Muchas gracias por el testing, ya mismo subiré las soluciones!
Y también, muchas gracias por subirlo a una branch en GitHub, usaré ese para modificar y actualizar el código.
 

Diego Mertens

Dartrix Joven
Actualización 18/09:
  • Resuelto el bug que hacía que la cadena continuara al ser derrotado por el Pokémon salvaje.
  • Resuelto el bug que hacía que la cadena se rompiera al capturar al Pokémon.
  • Agregada la opción de ver un repositorio para ver los cambios más fácilmente.
 

marios92

Aprendiz de leyenda
There isn't much to update about it, is there?
It looks like a finished feature that you can modify at will if you want.

Both games' codebases are built very very similarly, so it should be possible yeah.
But this?

Por hacer:
  • Añadir Pokémon raros a las rutas (que normalmente no aparecen) cuando la cadena suba.
  • Aumentar la probabilidad de que el Pokémon que buscas aparezca cuando la cadena suba.
  • Hacer que Pokémon con menor probabilidad de aparición sean más comunes cuando la cadena suba.
  • Evitar la ruptura de la cadena si se hace un combate contra un entrenador.
 

Lunos

Enfrentando a La Organización
Miembro insignia
But this?

Por hacer:
  • Añadir Pokémon raros a las rutas (que normalmente no aparecen) cuando la cadena suba.
  • Aumentar la probabilidad de que el Pokémon que buscas aparezca cuando la cadena suba.
  • Hacer que Pokémon con menor probabilidad de aparición sean más comunes cuando la cadena suba.
  • Evitar la ruptura de la cadena si se hace un combate contra un entrenador.
Fair enough. All I'm saying is that the core functionality is there, and anyone can just go and modify it as they see fit.
I grabbed this system (thanks for that btw @Diego Mertens) and tweaked it a lot in one of my personal projects for example.
Made it only work if the Player catches a Pokémon, made chained species appear more frequently and such.
But you can also wait until Diego logs in again.
 

marios92

Aprendiz de leyenda
Fair enough. All I'm saying is that the core functionality is there, and anyone can just go and modify it as they see fit.
I grabbed this system (thanks for that btw @Diego Mertens) and tweaked it a lot in one of my personal projects for example.
Made it only work if the Player catches a Pokémon, made chained species appear more frequently and such.
But you can also wait until Diego logs in again.
Wait, did you changed in "only if catches mon" like Let's Go? Its what im looking for: re-create that Lest'GO system. And you succesfully added "a particular rare mon appear only if chain is high"?
Would you mind to share your version?😶
 

Lunos

Enfrentando a La Organización
Miembro insignia
Wait, did you changed in "only if catches mon" like Let's Go? Its what im looking for: re-create that Lest'GO system. And you succesfully added "a particular rare mon appear only if chain is high"?
Would you mind to share your version?😶
To clarify, I didn't make battles work like they do in LGPE, in the sense that I didn't make battles work similarly to how they work in the Safari Zone or anything. I just made it so a chain is not being made if the Player doesn't catch the Pokémon they're fighting with.
As for wild encounters, I made it so there's something like an 85% of finding the same species you last fought if a chain is active.

I also changed some other things though, like the way this affects generating a shiny wild Pokémon, or how getting 'mons with perfect IVs by chaining works. It's basically what I said, you can just grab the code Diego wrote and then adjust and/or expand it in order to suit your needs.

In any case, here it is.
 
Última edición:

marios92

Aprendiz de leyenda
To clarify, I didn't make battles work like they do in LGPE, in the sense that I didn't make battles work similarly to how they work in the Safari Zone or anything. I just made it so a chain is not being made if the Player doesn't catch the Pokémon they're fighting with.
As for wild encounters, I made it so there's something like an 85% of finding the same species you last fought if a chain is active.

I also changed some other things though, like the way this affects generating a shiny wild Pokémon, or how getting 'mons with perfect IVs by chaining works. It's basically what I said, you can just grab the code Diego wrote and then adjust and/or expand it in order to suit your needs.

In any case, here it is.
Thank you!
Just a little OT question (does not make sense to open a thread for this):
Its possible to merge 2 different github repo about mods to include 2 or more hacks add-on in a rom?
I explain better: supposing i want both Combo Capture and DexNav in my hack, but both require a clean rom, so i will need to recompile a decomp hack just one time. So if i apply DexNav first and then i wanted to add Combo Capture, the rom is not clean anymore. You got what i mean?
 

Lunos

Enfrentando a La Organización
Miembro insignia
Thank you!
Just a little OT question (does not make sense to open a thread for this):
Its possible to merge 2 different github repo about mods to include 2 or more hacks add-on in a rom?
As in merging different features made using the decomps in one single project? Yes, it is possible.
Git has functions such as git cherry-pick and git pull to incorporate different commits or branches into your project.
I explain better: supposing i want both Combo Capture and DexNav in my hack, but both require a clean rom, so i will need to recompile a decomp hack just one time. So if i apply DexNav first and then i wanted to add Combo Capture, the rom is not clean anymore. You got what i mean?
You don't modify a ROM when you work with the decomps, so it's pointless to worry about it.

If you intend to use a ROM generated using a decomp based project for binary hacking purposes, you really should just not.
While it generates a ROM, the compiler can and will shift stuff around to accomodate custom changes like the ones presented in this thread nicely and make sure everything works. As a result, this process is highly likely to break compatibility with the tools you'd use in binary hacking, which expect the things they need to read to be at very specific areas of the ROM.
 

marios92

Aprendiz de leyenda
As in merging different features made using the decomps in one single project? Yes, it is possible.
Git has functions such as git cherry-pick and git pull to incorporate different commits or branches into your project.

You don't modify a ROM when you work with the decomps, so it's pointless to worry about it.

If you intend to use a ROM generated using a decomp based project for binary hacking purposes, you really should just not.
While it generates a ROM, the compiler can and will shift stuff around to accomodate custom changes like the ones presented in this thread nicely and make sure everything works. As a result, this process is highly likely to break compatibility with the tools you'd use in binary hacking, which expect the things they need to read to be at very specific areas of the ROM.
I know you cant add ASM routines (and binary hacking in general) after a decomp, but you can BEFORE?
Or include some ASM routines during the decomp project development? I see in various repo project that there' some asm routines inside various folder.
 

Lunos

Enfrentando a La Organización
Miembro insignia
I know you cant add ASM routines (and binary hacking in general) after a decomp, but you can BEFORE?
Or include some ASM routines during the decomp project development? I see in various repo project that there' some asm routines inside various folder.
What do you mean by "before"? How would you do binary hacking "before" building a ROM using the decomps?
The decomps will only build a ROM containing the data that is present within the decompiled source code.
Do you think you can inject ASM routines to a ROM and then use that ROM with the decomps afterward or something...?
Or include some ASM routines during the decomp project development? I see in various repo project that there' some asm routines inside various folder.
Yes, that you can do. Hell, that's how it all begins, with the code that conforms a ROM written in ASM obtained through a disassembler like IDA Pro.
The thing is that there's no point in writing code in ASM for the decomps when you can just work with C which is more readable and easier to handle.
 

marios92

Aprendiz de leyenda
What do you mean by "before"? How would you do binary hacking "before" building a ROM using the decomps?
The decomps will only build a ROM containing the data that is present within the decompiled source code.
Do you think you can inject ASM routines to a ROM and then use that ROM with the decomps afterward or something...?
I meant to inject some ASM on clean rom, and then use a decomp on that instead of clean rom, doing some C modding, and recompile in the end. But now i see its sound pretty stupid XD
And i know, everybody says that modding in C is better than ASM, but i still found C too confusionary right now:rolleyes: (i mean, this Combo Capture doesnt seem that hard, but i've seen some projects where i got nothing XD)
 
Arriba