Registrarse

[pokeruby] Implementando habilidades nuevas

Lumbreon

Soy nuevo XD :3
¡NUEVAS HABILIDADES PARA POKERUBY!

He estado toqueteando un poco por aquí y por allá los archivos referentes al
combate y logre implementar algunas habilidades, así que me pareció buena
idea compartirlas aquí.

También me gustaría que en este mismo tema compartieran métodos para implementar nuevas habilidades de 4ta generación en adelante.

Aquí la lista de las que van de momento.


Asi que vamos por partes...

Primero hay que hacer que el juego reconozca las habilidades que vayamos a agregar

Vamos al archivo "pokeruby\include\constants\abilities.h" y definimos la nueva habilidad de la misma forma en la que se definen las anteriores, si quisiésemos agregar la habilidad adaptable, quedaría de la siguiente forma despues de "air lock".
"#define ABILITY_ADAPTABILITY 79".

Ahora en el archivo "pokeruby\data\text\ability_names.inc" Añadimos el nombre de la habilidad como se mostrará en el juego, claro esto después de "air lock"...
cabe destacar que el nombre no puede tener mas de 12 caracteres.
Luego hacemos lo propio en el archivo de descripciones dentro de la misma carpeta, aquí recomiendo que busquen "AirLock" y copien la linea entera luego remplacen con la información de la habilidad nueva. Esto lo tienen que hacer dos veces, porque primero se define la descripción y al final del archivo se define el puntero.

Ya solo resta ponerle la habilidad a un pokémon a para comprobar y listo, solo faltaría darle su función a esa habilidad.

Ahora algunas habilidades

vamos al archivo "battle_4.h" en la carpeta "pokeruby\src\battle" y buscamos "check stab"ahi veremos la función que checkea si el tipo del ataque coincide con el tipo del pokémon.
Bien... Solo hay que reemplazar esa funcion por estas 2
Código:
		if (gBattleMons[gBankAttacker].ability == ABILITY_RECKLESS || gBattleMons[gBankAttacker].ability == ABILITY_TECHNICIAN)
         {   if ((gBattleMoves[gCurrentMove].effect == EFFECT_DOUBLE_EDGE || gBattleMoves[gCurrentMove].effect == EFFECT_RECOIL_IF_MISS || gBattleMoves[gCurrentMove].effect == EFFECT_RECOIL) && gBattleMons[gBankAttacker].ability == ABILITY_RECKLESS)
                gBattleMoveDamage = gBattleMoveDamage * 15; // Reckless		
            if (gBattleMoves[gCurrentMove].power <= 60 && gBattleMons[gBankAttacker].ability == ABILITY_TECHNICIAN)
                gBattleMoveDamage = gBattleMoveDamage * 50; // Technician
			
				gBattleMoveDamage = gBattleMoveDamage / 10;
		}	
        //check stab
        if ((gBattleMons[gBankAttacker].type1 == move_type || gBattleMons[gBankAttacker].type2 == move_type) && gBattleMons[gBankAttacker].ability != ABILITY_ADAPTABILITY)
        {
            gBattleMoveDamage = gBattleMoveDamage * 15;
            gBattleMoveDamage = gBattleMoveDamage / 10;
        }
		if ((gBattleMons[gBankAttacker].type1 == move_type || gBattleMons[gBankAttacker].type2 == move_type) && gBattleMons[gBankAttacker].ability == ABILITY_ADAPTABILITY)
        {
            gBattleMoveDamage = gBattleMoveDamage * 20;
            gBattleMoveDamage = gBattleMoveDamage / 10;
        }

Y listo...


Bueno, casi... Para que esto funcione, deben definir las habilidades tal cual como yo lo hice en el archivo "abilities.h". De esta forma
Código:
#define ABILITY_ADAPTABILITY 78
#define ABILITY_RECKLESS 79
#define ABILITY_TECHNICIAN 80
Y ya está, estaré actualizando con las demás habilidades que dejé en la lista de arriba, también me gustaría que colaborasen añadiendo más habilidades en este tema para colaborar entre nosotros y añadir muchas más.
 
Última edición:

Lunos

Enfrentando a La Organización
Miembro insignia
Re: (pokeruby) Implementando habilidades nuevas

Pues el tutorial es sencillo de comprender, eso si, hay que dejar en claro que aquí solo se está explicando lo que viene siendo la base para añadir nuevas habilidades, y que añadir su función o sus funciones es una tarea distinta, y dependiendo del caso, mucho mas complicada.

también me gustaría que colaborasen añadiendo más habilidades en este tema para colaborar entre nosotros y añadir muchas más
Pues noté que en el post principal mencionas algunas implementaciones de habilidades hechas por mi, pero no has enlazado nada al post principal. Debido a eso, decidí dejar por aquí un poco de mi trabajo, directo desde mi repositorio (Pokeruby493).

Dejando Adaptability, Reckless y Technician de lado, pues este post ya las cubre, yo tengo:
-Aftermath/Resquicio
-Anger Point/Irascible (aunque de hecho la implementación fue hecha por DoesntKnowHowToPlay, asi que creditos a él.)
-Bad Dreams/Mal Sueño (Nota: Por algun motivo que no comprendo, no funciona contra un Seedot.)
-Filter/Filtro (Ctrl+F "ABILITY_FILTER")
-Heatproof/Ignífugo
-Iron Fist/Puño Férreo
-No Guard/Indefenso, aunque está un poco a medias. No pude hacer que funcione con los movimientos OHKO.
-Poison Heal/Antidoto (implementado por un conocido mio llamado ItsJustChris, el credito es suyo)

Tambien están Snow Warning/Nevada, Snow Cloak/Manto Niveo y Ice Body/Gélido, implementados por Fontbane y añadidos al proyecto mediante Pull Request.
https://github.com/LOuroboros/pokeruby493/pull/1

Si alguien encuentra algun error en alguna de estas implementaciones, haganmelo saber.
Naturalmente, los creditos donde corresponden.

Espero que mas gente se cope y podamos tener una buena cantidad de contenido para usar en nuestros respectivos proyectos.
 
Última edición:

Kaktus

Miembro insignia
Miembro insignia
Respuesta: (pokeruby) Implementando habilidades nuevas

¡Wow!

Me gusta que poco a poco os vayáis animando con decompilación y además hagáis tutoriales. Sin duda, saber donde encontrar lo que necesitamos cambiar concretamente sin tener que investigarlo, gracias a tener esa información recogida en un post, es un puntazo.

Eso sí, te recomendaría que incluyeras código a modo de ejemplo para que los usuarios sin mucha experiencia sepan a qué te refieres, o incluso para los que ya llevamos un tiempo, que nunca vienen mal a modo de referencia.

Si la idea es aportar la mayor cantidad de habilidades posibles, o recopilarlas, te recomendaría que crearas un fork de pokeruby o pokeemerald (el segundo mejor :3) y que todos pudieran contribuir allí, a la par que seguir dejando por aquí los respectivos códigos para aquellos que lo necesiten para algo puntual.

¡Sigue con esa buena iniciativa, buen tuto y un saludo!
 

Lumbreon

Soy nuevo XD :3
Respuesta: (pokeruby) Implementando habilidades nuevas

¡Wow!

Me gusta que poco a poco os vayáis animando con decompilación y además hagáis tutoriales. Sin duda, saber donde encontrar lo que necesitamos cambiar concretamente sin tener que investigarlo, gracias a tener esa información recogida en un post, es un puntazo.

Eso sí, te recomendaría que incluyeras código a modo de ejemplo para que los usuarios sin mucha experiencia sepan a qué te refieres, o incluso para los que ya llevamos un tiempo, que nunca vienen mal a modo de referencia.

Si la idea es aportar la mayor cantidad de habilidades posibles, o recopilarlas, te recomendaría que crearas un fork de pokeruby o pokeemerald (el segundo mejor :3) y que todos pudieran contribuir allí, a la par que seguir dejando por aquí los respectivos códigos para aquellos que lo necesiten para algo puntual.

¡Sigue con esa buena iniciativa, buen tuto y un saludo!
Gracias por el apoyo y las recomendaciones las tendré muy en cuenta.

Esta habilidad lo que hace es convertir todos los ataque al tipo normal. Para añadirla hay que ir a pokeruby\src\battle\battle_4.c y buscamos esto"static void atk06_typecalc(void)" y veremos esto:
Código:
static void atk06_typecalc(void)
{
    int i = 0;
    u8 move_type;
    if (gCurrentMove != MOVE_STRUGGLE)
    {
        if (gBattleStruct->dynamicMoveType)
            move_type = gBattleStruct->dynamicMoveType & 0x3F;
        else
            move_type = gBattleMoves[gCurrentMove].type;
Con mas cosas dentro de la misma función pero esto es suficiente para dar contexto.
Bueno, debajo de eso pegamos el siguiente código en una linea nueva.
Código:
if (gBattleMons[gBankAttacker].ability == ABILITY_NORMALIZE && gBattleMoves[gCurrentMove].type != TYPE_NORMAL)
		{
			gBattleStruct->dynamicMoveType = TYPE_NORMAL;
			move_type = TYPE_NORMAL;
		}
Y si hicimos los cambios correspondiente a la habilidad que expliqué en el post principal, ya debería estar funcionando.
Esta habilidad hasta la 4ta generación funcionaba solo bloqueando los ataques "One Hit KO" pero desde la 5ta generación a parte de eso, también impide que el pokémon caiga debilitado de un golpe si sus Ps. Estaban al máximo.

Para hacer que tenga sus dos efectos hay que ir al archivo "pokeruby\src\battle\battle_4.c" y buscar esto "(hold_effect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality)" y en una linea nueva justo arriba pegamos este código:
Código:
if (gBattleMons[gBankTarget].ability == ABILITY_STURDY && gBattleMons[gBankTarget].maxHP == gBattleMons[gBankTarget].hp && gBattleMons[gBankAttacker].ability != ABILITY_MOLD_BREAKER)
    {
        gProtectStructs[gBankTarget].endured = 1;
    }
Para que quede tal que así junto con lo que buscamos previamente.
Código:
if (gBattleMons[gBankTarget].ability == ABILITY_STURDY && gBattleMons[gBankTarget].maxHP == gBattleMons[gBankTarget].hp && gBattleMons[gBankAttacker].ability != ABILITY_MOLD_BREAKER)
    {
        gProtectStructs[gBankTarget].endured = 1;
    }
    if (hold_effect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality)
Ya con esto el pokémon se quedará a un Ps. Y ejecutará el mismo script de "Endure" o "Aguante".
 

Lunos

Enfrentando a La Organización
Miembro insignia
Re: Respuesta: (pokeruby) Implementando habilidades nuevas

En "battle.util.c"
Original
Código:
            case ABILITY_AFTERMATH:
                if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
                 && gBattleMons[gBankTarget].hp == 0
                 && (gBattleMoves[move].flags & F_MAKES_CONTACT))
                {
                    gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4;
                    if (gBattleMoveDamage == 0)
                        gBattleMoveDamage = 1;
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_AftermathDmg;
                    effect++;
                }
                break;
Con Fix
Código:
            case ABILITY_AFTERMATH:
                if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
                 && gBattleMons[gBankTarget].hp == 0)
                {
                    gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4;
                    if (gBattleMoveDamage == 0)
                        gBattleMoveDamage = 1;
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_AftermathDmg;
                    effect++;
                }
                break;
Según yo es un arreglo, quité el comprobante de sí el ataque hace contacto o no, porque si no mal recuerdo, el único requisito para que esta habilidad se active es que el pokémon sea debilitado.

Y en "battle_scripts_1.s" queda agregar un "hitanimation USER" en la primera linea del script que ejecuta esta función (BattleScript_AftermathDmg) si se quiere que haga la animación de ser golpeado.
Tu corrección a Aftermath está mal, y lo de añadir una animación es enteramente opcional. Recien ahora le estoy echando un vistazo apropiadamente, al reimplementar la habilidad en un nuevo repositorio.

Aftermath unicamente se activa si el pokémon que la posee es debilitado por un ataque fisico, y como tal, no produce ninguna animación en los juegos de la 4ta Generación y posteriores.
Lo ultimo no es que esté incorrecto ni nada, pero si es algo opcional. Mi implementación no posee una, porque mi objetivo era replicar de la manera mas fiel posible la habilidad como GF la desarrolló.

EDITO:
En "battle_util.c"
Original
Código:
            case ABILITY_ANGER_POINT:
                if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gCritMultiplier > 1 && !gProtectStructs[gBankAttacker].confusionSelfDmg && gBattleMons[gBankTarget].hp != 0 && (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special))
                {
                    gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] = 12;
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_AngerPointBoost;
                    effect++;
                }
                break;
Con Fix
Código:
				case ABILITY_ANGER_POINT:
                if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gCritMultiplier > 1 && !gProtectStructs[gBankAttacker].confusionSelfDmg && gBattleMons[gBankTarget].hp != 0 && (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special))
                {
                    gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] = 12;
					gBattleStruct->animArg1 = 0xF;
                    gBattleStruct->animArg2 = 0;					
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_AngerPointBoost;
                    effect++;
                }
                break;
Aquí el cambio es meramente estético, pero me parece necesario.
Ya que con las lineas que agregué se prepara el terreno para que en el script de combate se haga la animación de aumento de estadísticas, la cual no se hace con el método original posteado por Doesnt.

En "battle_scripts_1.s"
Original
Código:
BattleScript_AngerPointBoost::
	printstring BATTLE_TEXT_AngerPointBoost
	waitmessage 64
	return
Con fix
Código:
BattleScript_AngerPointBoost::
	playanimation TARGET, B_ANIM_STATS_CHANGE, sANIM_ARG1
	printstring BATTLE_TEXT_AngerPointBoost
	waitmessage 64
	return
Nada mas que agregar, solo hacemos que ejecute la animación que declaramos anteriormente.
Lo mismo pasa aquí, Anger Point no activa ninguna animación de subida de estadisticas. Quizá sea por eso que la implementación de Doesnt no tiene una, porque entonces no seria fiel a como funciona la habilidad en los juegos oficiales.
 
Última edición:

Lumbreon

Soy nuevo XD :3
Respuesta: (pokeruby) Implementando habilidades nuevas

Lo siento Lunos por ese pequeño desliz :( debí informarme correctamente antes de corregir un trabajo ajeno, la verdad fue muy tonto, así que ahora traigo una corrección correcta y acorde al funcionamiento de la habilidad en los juegos originales.
(Lo de las animaciónes debí dejarlo, al menos para mi gusto quedaba muy bien, pero me precipité al borrarlo :v)
se trata de "Skill link" o "Encadenado", ya que la manera en que presenté esta habilidad en el post principal(que francamente no sé de donde la saqué :v), lo que hace es amplificar el daño de los movimientos "Multi hit".
Cuando originalmente lo que hace es que éstos siempre impacten 5 veces, para conseguir esto ultimo hay que hacer lo siguiente.

Hay que ir al archivo "pokeruby/src/battle/battle_4.c" y vamos a buscar esto "atk8D_setmultihitcounter" donde encontraremos la siguiente función:
Código:
static void atk8D_setmultihitcounter(void)
{
    if (T2_READ_8(gBattlescriptCurrInstr + 1))
        gMultiHitCounter = T2_READ_8(gBattlescriptCurrInstr + 1);
    else
    {
        gMultiHitCounter = Random() & 3;
        if (gMultiHitCounter > 1)
            gMultiHitCounter = (Random() & 3) + 2;
        else
            gMultiHitCounter += 2;

    }
    gBattlescriptCurrInstr += 2;
}
La cual vamos a remplazar por esta:
Código:
static void atk8D_setmultihitcounter(void)
{
    if (T2_READ_8(gBattlescriptCurrInstr + 1))
        gMultiHitCounter = T2_READ_8(gBattlescriptCurrInstr + 1);
    else
    {
        gMultiHitCounter = Random() & 3;
        if (gMultiHitCounter > 1)
            gMultiHitCounter = (Random() & 3) + 2;
        else
            gMultiHitCounter += 2;
		
		if (gBattleMons[gBankAttacker].ability == ABILITY_SKILL_LINK)
            gMultiHitCounter = 5;
    }
    gBattlescriptCurrInstr += 2;
}
Y listo ya estaría, cabe destacar que esto lo saque del battle engine de dizzyegg, el cual usaría pero por alguna razón no me compila cuando lo copio a mi carpeta de pokeemerald. :(

Esta habilidad hace el pokémon que la posea pueda atacar a pokémon de tipo fantasma con ataques de tipo normal y lucha.
En el mismo archivo (battle_4.c) buscamos lo siguiente:
Código:
{
            while (gTypeEffectiveness[i]!= TYPE_ENDTABLE)
            {
                if (gTypeEffectiveness[i] == TYPE_FORESIGHT)
                {
                    if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) <------ esto lo modificamos
                        break;
                    i += 3;
                    continue;
                }
Donde señalé colocaremos esto:
Código:
while (gTypeEffectiveness[i]!= TYPE_ENDTABLE)
            {
                if (gTypeEffectiveness[i] == TYPE_FORESIGHT)
                {
                    if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT || gBattleMons[gBankAttacker].ability == ABILITY_SCRAPPY) <----- colocamos el comprobante de la habilidad
                        break;
                    i += 3;
                    continue;
                }
 

Lunos

Enfrentando a La Organización
Miembro insignia
Re: (pokeruby) Implementando habilidades nuevas

Oye @Lumbreon, elimina mi implementación de la habilidad Filtro de tu hack/repositorio, porque está mal hecha.
Aquí puedes encontrarla bien hecha, Ctrl+F "ABILITY_FILTER".
https://pastebin.com/HRESyn3A
La pongo en un Pastebin porque la tengo puesta en un repositorio aun sin subir.

En fin, a lo que venia.
Mi implementación de "Bad Dreams" (la habilidad de Darkrai) tiene un pequeño problema, y es rarisimo.
Primero que nada y antes que todo describirla, Bad Dreams es una habilidad que le quita 1/8 de HP al oponente al final de cada turno, siempre y cuando esté dormido.

En si, la habilidad está funcionando correctamente contra un Wurmple, contra un Zigzagoon o contra un Poochyena, pero al probarla contra un Seedot, no funciona.

Lo que estoy haciendo para testear la habilidad basicamente es:
1) Darsela a Torchic.
2) Darle el movimiento Spore, para que pueda dormir enemigos sin error.
3) Entro en batalla, tiro Spore y luego puro Focus Energy para que pasen los turnos y yo pueda compruebar el efecto de Bad Dreams.

El resultado es que al final del turno, estando Wurmple/Poochyena/Zigzagoon dormidos, ellos pierden HP y la linea de texto que le asigné a Bad Dreams se muestra en pantalla.
La habilidad basicamente funciona correctamente.

Pero con Seedot, la habilidad no se activa en lo absoluto. Él se queda dormido, y el turno pasa normalmente.

Si tú (Lumineon) o alguien más tiene alguna idea sobre que puede estar pasando aquí, no dude en contactarme sea por aquí o por Discord (Lunos#4026).
El codigo es exactamente el mismo que enlacé ahi arriba. Mismas modificaciones tambien, excepto por lo que sea que hice en include\constants\egg_hatch.h. No tengo idea de que sea esa modificación, pero no está relacionada a la habilidad en lo absoluto y por eso no lo repliqué.

Agradezco de antemano por leer.

EDITO: Por cierto, tu implementación de Skill Link es completamente incorrecta.
El efecto de esa habilidad es hacer que los movimientos que golpean multiples veces, como por ejemplo Bullet Seed, Comet Punch y tal, siempre den 5 golpes en lugar de un numero aleatorio entre 2 y 5. No aumenta su poder de ninguna forma, como estás mostrando tú en el post principal.

EDITO2: Y bueno, poner Technician y Reckless dentro de una función que comprueba el daño por tipos no es exactamente correcto, aunque si las habilidades en si funcionan, pues que mas dá supongo.

EDITO3: Tras notar lo de Skill Link, decidí intentar hacer la habilidad yo mismo, a ver si podia.
.... Y pude.

Tras insertar el nombre, la descripción y definir la habilidad en include\constants\abilities.h, hay que modificar la función "atk8D_setmultihitcounter" del archivo src\battle\battle_4.c de la siguiente forma:
Código:
static void atk8D_setmultihitcounter(void)
{
    if (T2_READ_8(gBattlescriptCurrInstr + 1))
        gMultiHitCounter = T2_READ_8(gBattlescriptCurrInstr + 1);
    if (gBattleMons[gBankAttacker].ability == ABILITY_SKILL_LINK)
        gMultiHitCounter = 5;
    else
    {
        gMultiHitCounter = Random() & 3;
        if (gMultiHitCounter > 1)
            gMultiHitCounter = (Random() & 3) + 2;
        else
            gMultiHitCounter += 2;
    }
    gBattlescriptCurrInstr += 2;
}
Guardar, darsela a un pokémon para probar y compilar.

EDITO4: Tu implementación de Motor Drive funciona, pero faltó pulirla. Tiene un montón de codigo inutil.
Aquí dejo la habilidad tras retocarla un poco. Si ves algo mal o incorrecto, tú avisame.

BattleScript
Código:
BattleScript_MoveSpeedDrain::
	attackstring
	pause 32
	playanimation TARGET, B_ANIM_STATS_CHANGE, sANIM_ARG1	
	printstring BATTLE_TEXT_SpeedRisen
	waitmessage 64	
	goto BattleScript_MoveEnd
Efecto de la habilidad (src\battle\battle_util.c)
Código:
case ABILITY_MOTOR_DRIVE:
	if (moveType == TYPE_ELECTRIC && gBattleMoves[move].power != 0)
	{
		if (gBattleMons[bank].statStages[STAT_STAGE_SPEED] < 0xC)
			gBattleMons[bank].statStages[STAT_STAGE_SPEED]++;
		gBattleStruct->animArg1 = 0x11;
		gBattleStruct->animArg2 = 0;
		gBattlescriptCurrInstr = BattleScript_MoveSpeedDrain;
		effect = 2;
	}
	break;
Ya el formato, los espacios y tal lo arregla cada uno a la hora de insertar el codigo.
 
Última edición:

Lumbreon

Soy nuevo XD :3
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Oye @Lumbreon, elimina mi implementación de la habilidad Filtro de tu hack/repositorio, porque está mal hecha.
Aquí puedes encontrarla bien hecha, Ctrl+F "ABILITY_FILTER".
https://pastebin.com/HRESyn3A
La pongo en un Pastebin porque la tengo puesta en un repositorio aun sin subir.

En fin, a lo que venia.
Mi implementación de "Bad Dreams" (la habilidad de Darkrai) tiene un pequeño problema, y es rarisimo.
Primero que nada y antes que todo describirla, Bad Dreams es una habilidad que le quita 1/8 de HP al oponente al final de cada turno, siempre y cuando esté dormido.

En si, la habilidad está funcionando correctamente contra un Wurmple, contra un Zigzagoon o contra un Poochyena, pero al probarla contra un Seedot, no funciona.

Lo que estoy haciendo para testear la habilidad basicamente es:
1) Darsela a Torchic.
2) Darle el movimiento Spore, para que pueda dormir enemigos sin error.
3) Entro en batalla, tiro Spore y luego puro Focus Energy para que pasen los turnos y yo pueda compruebar el efecto de Bad Dreams.

El resultado es que al final del turno, estando Wurmple/Poochyena/Zigzagoon dormidos, ellos pierden HP y la linea de texto que le asigné a Bad Dreams se muestra en pantalla.
La habilidad basicamente funciona correctamente.

Pero con Seedot, la habilidad no se activa en lo absoluto. Él se queda dormido, y el turno pasa normalmente.

Si tú (Lumineon) o alguien más tiene alguna idea sobre que puede estar pasando aquí, no dude en contactarme sea por aquí o por Discord (Lunos#4026).
El codigo es exactamente el mismo que enlacé ahi arriba. Mismas modificaciones tambien, excepto por lo que sea que hice en include\constants\egg_hatch.h. No tengo idea de que sea esa modificación, pero no está relacionada a la habilidad en lo absoluto y por eso no lo repliqué.

Agradezco de antemano por leer.

EDITO: Por cierto, tu implementación de Skill Link es completamente incorrecta.
El efecto de esa habilidad es hacer que los movimientos que golpean multiples veces, como por ejemplo Bullet Seed, Comet Punch y tal, siempre den 5 golpes en lugar de un numero aleatorio entre 2 y 5. No aumenta su poder de ninguna forma, como estás mostrando tú en el post principal.

EDITO2: Y bueno, poner Technician y Reckless dentro de una función que comprueba el daño por tipos no es exactamente correcto, aunque si las habilidades en si funcionan, pues que mas dá supongo.

EDITO3: Tras notar lo de Skill Link, decidí intentar hacer la habilidad yo mismo, a ver si podia.
.... Y pude.

Tras insertar el nombre, la descripción y definir la habilidad en include\constants\abilities.h, hay que modificar la función "atk8D_setmultihitcounter" del archivo src\battle\battle_4.c de la siguiente forma:
Código:
static void atk8D_setmultihitcounter(void)
{
    if (T2_READ_8(gBattlescriptCurrInstr + 1))
        gMultiHitCounter = T2_READ_8(gBattlescriptCurrInstr + 1);
    if (gBattleMons[gBankAttacker].ability == ABILITY_SKILL_LINK)
        gMultiHitCounter = 5;
    else
    {
        gMultiHitCounter = Random() & 3;
        if (gMultiHitCounter > 1)
            gMultiHitCounter = (Random() & 3) + 2;
        else
            gMultiHitCounter += 2;
    }
    gBattlescriptCurrInstr += 2;
}
Guardar, darsela a un pokémon para probar y compilar.

EDITO4: Tu implementación de Motor Drive funciona, pero faltó pulirla. Tiene un montón de codigo inutil.
Aquí dejo la habilidad tras retocarla un poco. Si ves algo mal o incorrecto, tú avisame.

BattleScript
Código:
BattleScript_MoveSpeedDrain::
	attackstring
	pause 32
	playanimation TARGET, B_ANIM_STATS_CHANGE, sANIM_ARG1	
	printstring BATTLE_TEXT_SpeedRisen
	waitmessage 64	
	goto BattleScript_MoveEnd
Efecto de la habilidad (src\battle\battle_util.c)
Código:
case ABILITY_MOTOR_DRIVE:
	if (moveType == TYPE_ELECTRIC && gBattleMoves[move].power != 0)
	{
		if (gBattleMons[bank].statStages[STAT_STAGE_SPEED] < 0xC)
			gBattleMons[bank].statStages[STAT_STAGE_SPEED]++;
		gBattleStruct->animArg1 = 0x11;
		gBattleStruct->animArg2 = 0;
		gBattlescriptCurrInstr = BattleScript_MoveSpeedDrain;
		effect = 2;
	}
	break;
Ya el formato, los espacios y tal lo arregla cada uno a la hora de insertar el codigo.
Con respecto a Skill Link, estoy seguro de que lo corregí, pero no lo coloqué en el post principal.
Por lo de Motor Drive, pues un poco mal de mi parte... Peeeeeero, fue de los primeros códigos que hice así que no me sorprende que dé algo de asco :v sí lo hiciese ahora mismo, me ocuparía mucho menos código.
Ahora sí, con respecto a Bad Dreams, Tengo la solución.
Lo que hice(Guíandome más que todo del battle engine de dizzyegg) fue mover el código para que se active al final de cada turno, los cambios son estos.
Código:
bool32 IsBattlerAlive(u8 battlerId) // esto lo pegan en cualquier sitio
{
    if (gBattleMons[battlerId].hp == 0)
        return FALSE;
    else if (battlerId >= gBattlersCount)
        return FALSE;
    else if (gAbsentBattlerFlags & gBitTable[battlerId])
        return FALSE;
	else
		return TRUE;
}
en la función "atk80_manipulatedamage"
Código:
{
    switch (T2_READ_8(gBattlescriptCurrInstr + 1))
    {
    case 0:
        gBattleMoveDamage *= -1;
        break;
    case 1:
        gBattleMoveDamage /= 2;
        if (gBattleMoveDamage == 0)
            gBattleMoveDamage = 1;
        if ((gBattleMons[gBankTarget].maxHP / 2) < gBattleMoveDamage)
            gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2;
        break;
    case 2:
        gBattleMoveDamage *= 2;
        break;
	case 3:
	gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 8;
        if (gBattleMoveDamage == 0)
            gBattleMoveDamage = 1;
        break;
    }

    gBattlescriptCurrInstr += 2;
}
//Aquí solo agregamos el "case 3" pero si quieren reemplazan toda la función original por esta
En sitios varios
Código:
static void atkf8_trygetbaddreamstarget(void);//en cualquier sitio al principio del archivo

en "gBattleScriptingCommandsTable"
añadimos otra entrada a la tabla despues de:
atkF7_finishturn,
atkf8_trygetbaddreamstarge,//la nueva entrada es esta

y luego al final del archivo, la función que hace la magía:
static void atkf8_trygetbaddreamstarge(void)
{
    u8 badDreamsMonSide = GetBattlerSide(gBankAttacker);
	for (;gBankTarget < gBattlersCount; gBankTarget++)
    {
        if (GetBattlerSide(gBankTarget) == badDreamsMonSide)
            continue;
        if (gBattleMons[gBankTarget].status1 & STATUS_SLEEP && IsBattlerAlive(gBankTarget))
            break;
    }

    if (gBankTarget >= gBattlersCount)
        gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
    else
        gBattlescriptCurrInstr += 5;
}
buscamos "trainerslideout"
seleccionamos toda la macro y la reemplazamos por esto:
Código:
.macro trygetbaddreamstarget address
	.byte 0xf8
	.4byte \address
	.endm
	
	.macro trainerslideout bank
	.byte 0xf9
	.byte \bank
	.endm
Esto lo explicaré un poco(muy poco):
Lo que hacemos es crear una macro que se puede usar a la hora de scriptear scripts de batalla.
En la macro que buscamos lo único que se altera es su valor, ya que por alguna razón tiene que quedar de última.
y en la macro que creamos es la que ejecutaremos con la función que se coloca en src/battle/battle_4.c
Borramos la funcion o "case" de bad dreams creado con el método de Lunos y pegamos este en despues de el "case" de la habilidad "Rain Dish"
Código:
case ABILITY_BAD_DREAMS:
                if (gBattleMons[BATTLE_OPPOSITE(bank)].status1 & STATUS_SLEEP || gBattleMons[BATTLE_OPPOSITE(bank)].status1 & STATUS_SLEEP)
                {
                    BattleScriptPushCursorAndCallback(BattleScript_BadDreamsDmg);
                    effect++;
                }
                break;
Por ultimo en "data/battle_scripts_1.s" Reemplazamos el Script de bad dreams(este: BattleScript_BadDreamsDmg) por este
Código:
BattleScript_BadDreamsDmg::
	setbyte gBankTarget, 0
BattleScript_BadDreamsLoop:
	trygetbaddreamstarget BattleScript_BadDreamsEnd
	manipulatedamage 3
	orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000
	printstring BATTLE_TEXT_BadDreamsDmg
	waitmessage 0x40
	healthbarupdate TARGET
	datahpupdate TARGET
	tryfaintmon TARGET, FALSE, NULL
	atk24 BattleScript_BadDreamsIncrement
BattleScript_BadDreamsIncrement:
	addbyte gBankTarget, 1
	goto BattleScript_BadDreamsLoop
BattleScript_BadDreamsEnd::
	end3
Y si no me salté nada ya estaría.
 
Última edición:

Lunos

Enfrentando a La Organización
Miembro insignia
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Ahora sí, con respecto a Bad Dreams, Tengo la solución.
Lo que hice(Guíandome más que todo del battle engine de dizzyegg) fue mover el código para que se active al final de cada turno, los cambios son estos.
Código:
bool32 IsBattlerAlive(u8 battlerId) // esto lo pegan en cualquier sitio
{
    if (gBattleMons[battlerId].hp == 0)
        return FALSE;
    else if (battlerId >= gBattlersCount)
        return FALSE;
    else if (gAbsentBattlerFlags & gBitTable[battlerId])
        return FALSE;
	else
		return TRUE;
}
en la función "atk80_manipulatedamage"
Código:
{
    switch (T2_READ_8(gBattlescriptCurrInstr + 1))
    {
    case 0:
        gBattleMoveDamage *= -1;
        break;
    case 1:
        gBattleMoveDamage /= 2;
        if (gBattleMoveDamage == 0)
            gBattleMoveDamage = 1;
        if ((gBattleMons[gBankTarget].maxHP / 2) < gBattleMoveDamage)
            gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2;
        break;
    case 2:
        gBattleMoveDamage *= 2;
        break;
	case 3:
	gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 8;
        if (gBattleMoveDamage == 0)
            gBattleMoveDamage = 1;
        break;
    }

    gBattlescriptCurrInstr += 2;
}
//Aquí solo agregamos el "case 3" pero si quieren reemplazan toda la función original por esta
En sitios varios
Código:
static void atkf8_trygetbaddreamstarget(void);//en cualquier sitio al principio del archivo

en "gBattleScriptingCommandsTable"
añadimos otra entrada a la tabla despues de:
atkF7_finishturn,
atkf8_trygetbaddreamstarge,//la nueva entrada es esta

y luego al final del archivo, la función que hace la magía:
static void atkf8_trygetbaddreamstarge(void)
{
    u8 badDreamsMonSide = GetBattlerSide(gBankAttacker);
	for (;gBankTarget < gBattlersCount; gBankTarget++)
    {
        if (GetBattlerSide(gBankTarget) == badDreamsMonSide)
            continue;
        if (gBattleMons[gBankTarget].status1 & STATUS_SLEEP && IsBattlerAlive(gBankTarget))
            break;
    }

    if (gBankTarget >= gBattlersCount)
        gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
    else
        gBattlescriptCurrInstr += 5;
}
buscamos "trainerslideout"
seleccionamos toda la macro y la reemplazamos por esto:
Código:
.macro trygetbaddreamstarget address
	.byte 0xf8
	.4byte \address
	.endm
	
	.macro trainerslideout bank
	.byte 0xf9
	.byte \bank
	.endm
Esto lo explicaré un poco(muy poco):
Lo que hacemos es crear una macro que se puede usar a la hora de scriptear scripts de batalla.
En la macro que buscamos lo único que se altera es su valor, ya que por alguna razón tiene que quedar de última.
y en la macro que creamos es la que ejecutaremos con la función que se coloca en src/battle/battle_4.c
Borramos la funcion o "case" de bad dreams creado con el método de Lunos y pegamos este en despues de el "case" de la habilidad "Rain Dish"
Código:
case ABILITY_BAD_DREAMS:
                if (gBattleMons[BATTLE_OPPOSITE(bank)].status1 & STATUS_SLEEP || gBattleMons[BATTLE_OPPOSITE(bank)].status1 & STATUS_SLEEP)
                {
                    BattleScriptPushCursorAndCallback(BattleScript_BadDreamsDmg);
                    effect++;
                }
                break;
Por ultimo en "data/battle_scripts_1.s" Reemplazamos el Script de bad dreams(este: BattleScript_BadDreamsDmg) por este
Código:
BattleScript_BadDreamsDmg::
	setbyte gBankTarget, 0
BattleScript_BadDreamsLoop:
	trygetbaddreamstarget BattleScript_BadDreamsEnd
	manipulatedamage 3
	orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000
	printstring BATTLE_TEXT_BadDreamsDmg
	waitmessage 0x40
	healthbarupdate TARGET
	datahpupdate TARGET
	tryfaintmon TARGET, FALSE, NULL
	atk24 BattleScript_BadDreamsIncrement
BattleScript_BadDreamsIncrement:
	addbyte gBankTarget, 1
	goto BattleScript_BadDreamsLoop
BattleScript_BadDreamsEnd::
	end3
Y si no me salté nada ya estaría.
Muchisimas gracias, al rato lo probaré, aunque en principio mi implementación tambien se deberia de estar activando al final de cada turno. Definitivamente lo está haciendo, porque funciona con determinados pokémon. Pero Seedot... pues con Seedot no hay caso :/

Por cierto, le acabo de echar el ojo a tu implementación de Storm Drain en el post principal, y parece estar incompleta. Creo que te faltó darle la propiedad de la habilidad Lightning Rod donde, en batallas dobles, todo movimiento Tipo Agua que el oponente use se va automaticamente hacia el pokémon que tenga Storm Drain.
 

Lumbreon

Soy nuevo XD :3
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Muchisimas gracias, al rato lo probaré, aunque en principio mi implementación tambien se deberia de estar activando al final de cada turno. Definitivamente lo está haciendo, porque funciona con determinados pokémon. Pero Seedot... pues con Seedot no hay caso :/

Por cierto, le acabo de echar el ojo a tu implementación de Storm Drain en el post principal, y parece estar incompleta. Creo que te faltó darle la propiedad de la habilidad Lightning Rod donde, en batallas dobles, todo movimiento Tipo Agua que el oponente use se va automaticamente hacia el pokémon que tenga Storm Drain.
Tu implementación de bad dreams se activa al atacar a un pokémon con la habilidad (esto porque está en la parte donde se ven las habilidades que chequean el contacto, estas se activan al final de cada movimiento) por lo que asumo que en batallas dobles no le haría daño a pokémon que seleccione a otro objetivo y seguramente por eso no le hacia daño a seedot(porque intentaba usar venganza, ataque que afecta al usuario y no a otro objetivo).

En cuanto a storm drain supongo que dentro de un rato colocaré eso que dices por aquí(como dije, fue el primer código que hice, así que esta algo incompleto y cutre :v), muchas gracias por avisarme.

EDITO:No fue dificil lo de storm drain.

Aquí la modificación correspondiente:
En "src/battle/battle_util.c" buscan:
Código:
ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_LIGHTNING_ROD
y veremos este "if"
Código:
 if (gBattleMoves[move].type == TYPE_ELECTRIC
                && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_LIGHTNING_ROD, 0, 0)
                && gBattleMons[targetBank].ability != ABILITY_LIGHTNING_ROD)
lo reemplazan con este otro
Código:
if ((gBattleMoves[move].type == TYPE_ELECTRIC
                && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_LIGHTNING_ROD, 0, 0)
                && gBattleMons[targetBank].ability != ABILITY_LIGHTNING_ROD) 
				|| (gBattleMoves[move].type == TYPE_WATER
                && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_STORM_DRAIN, 0, 0)
                && gBattleMons[targetBank].ability != ABILITY_STORM_DRAIN))
y listo, ya redirecciona el ataque al usuario de la habilidad si es de tipo agua(el ataque).
 
Última edición:

Lunos

Enfrentando a La Organización
Miembro insignia
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Tu implementación de bad dreams se activa al atacar a un pokémon con la habilidad (esto porque está en la parte donde se ven las habilidades que chequean el contacto, estas se activan al final de cada movimiento) por lo que asumo que en batallas dobles no le haría daño a pokémon que seleccione a otro objetivo y seguramente por eso no le hacia daño a seedot(porque intentaba usar venganza, ataque que afecta al usuario y no a otro objetivo).
Ya, eso lo sé. El asunto es que, en principio, moverla a case ABILITYEFFECT_ENDTURN deberia de lidiar con eso, pero el resultado es que la habilidad deja de funcionar por completo u_u ...
Si veo el resto de las habilidades que se encuentran ahi, ¿supongo que es porque Aftermath afecta al oponente y no al jugador..?

En fin, al final, lo que acabé haciendo fue meter un poco de mano y revisar otras partes de battle_util.c para obtener ideas sobre como manejarlo, y la respuesta a la que llegué fue usar lo que se conoce como un "for loop".
Lo cierto es que pese a que leí al respecto, no llegué a entender la definición en si demasiado bien, pero me tiré un copy y paste guapo, guapo desde case ABILITYEFFECT_TRACE y pues... funciona todo lo mas correctamente.

Asi que en resumen, lo unico que hay que cambiarle a mi implementación como la muestro en GitHub, es el efecto de la habilidad en si dentro de src\battle\battle_util.c

Viejo:
Código:
case ABILITY_BAD_DREAMS:
                if ((gBattleMons[gBankAttacker].status1 & STATUS_SLEEP) && gBattleMons[gBankAttacker].hp != 0)
                {
                    gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
                    if (gBattleMoveDamage == 0)
                        gBattleMoveDamage = 1;
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_BadDreamsDmg;
                    effect++;
                }
                gBattleStruct->turnEffectsTracker++;
                break;
Nuevo:
Código:
case ABILITY_BAD_DREAMS:
            for (i = 0; i < gBattlersCount; i++)
            {
                if ((gBattleMons[gBankAttacker].status1 & STATUS_SLEEP) && gBattleMons[gBankAttacker].hp != 0)
                {
                    gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
                    if (gBattleMoveDamage == 0)
                        gBattleMoveDamage = 1;
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_BadDreamsDmg;
                    effect++;
					break;
                }
            }
            break;


Cualquier otro cambio que le quieran hacer a la habilidad, ya corre por cuenta de cada quien.
Yo por ejemplo creo que eliminaré la nueva string de texto que añadí para la habilidad. Es al dope, voy a tirar del Battle Script de Rough Skin con su string de texto propia y listo.

EDITO: Por cierto, ¿tú has probado tu corrección a Storm Drain? Porque que el proyecto compile no significa que tu codigo si o si vaya a funcionar.
 
Última edición:

Lumbreon

Soy nuevo XD :3
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Ya, eso lo sé. El asunto es que, en principio, moverla a case ABILITYEFFECT_ENDTURN deberia de lidiar con eso, pero el resultado es que la habilidad deja de funcionar por completo u_u ...
Si veo el resto de las habilidades que se encuentran ahi, ¿supongo que es porque Aftermath afecta al oponente y no al jugador..?

En fin, al final, lo que acabé haciendo fue meter un poco de mano y revisar otras partes de battle_util.c para obtener ideas sobre como manejarlo, y la respuesta a la que llegué fue usar lo que se conoce como un "for loop".
Lo cierto es que pese a que leí al respecto, no llegué a entender la definición en si demasiado bien, pero me tiré un copy y paste guapo, guapo desde case ABILITYEFFECT_TRACE y pues... funciona todo lo mas correctamente.

Asi que en resumen, lo unico que hay que cambiarle a mi implementación como la muestro en GitHub, es el efecto de la habilidad en si dentro de src\battle\battle_util.c

Viejo:
Código:
case ABILITY_BAD_DREAMS:
                if ((gBattleMons[gBankAttacker].status1 & STATUS_SLEEP) && gBattleMons[gBankAttacker].hp != 0)
                {
                    gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
                    if (gBattleMoveDamage == 0)
                        gBattleMoveDamage = 1;
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_BadDreamsDmg;
                    effect++;
                }
                gBattleStruct->turnEffectsTracker++;
                break;
Nuevo:
Código:
case ABILITY_BAD_DREAMS:
            for (i = 0; i < gBattlersCount; i++)
            {
                if ((gBattleMons[gBankAttacker].status1 & STATUS_SLEEP) && gBattleMons[gBankAttacker].hp != 0)
                {
                    gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
                    if (gBattleMoveDamage == 0)
                        gBattleMoveDamage = 1;
                    BattleScriptPushCursor();
                    gBattlescriptCurrInstr = BattleScript_BadDreamsDmg;
                    effect++;
					break;
                }
            }
            break;


Cualquier otro cambio que le quieran hacer a la habilidad, ya corre por cuenta de cada quien.
Yo por ejemplo creo que eliminaré la nueva string de texto que añadí para la habilidad. Es al dope, voy a tirar del Battle Script de Rough Skin con su string de texto propia y listo.

EDITO: Por cierto, ¿tú has probado tu corrección a Storm Drain? Porque que el proyecto compile no significa que tu codigo si o si vaya a funcionar.

A mi bad dreams no me funciona correctamente con ese método, pero puede que me falte retirar un cambio de mi forma, así que si lo pruebas y funciona correctamente en combates dobles con todos los pokémon dormidos entonces perfectamente.

En cuanto a storm drain, funciona, si te das cuenta uso el mismo código de lightingrod, pero con los parámetros que son necesarios para storm drain.
 

Lunos

Enfrentando a La Organización
Miembro insignia
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

A mi bad dreams no me funciona correctamente con ese método, pero puede que me falte retirar un cambio de mi forma, así que si lo pruebas y funciona correctamente en combates dobles con todos los pokémon dormidos entonces perfectamente.
Pues tienes tú razón. No funciona nada, nada bien en combates dobles, jajaja.
https://streamable.com/mb46a

Voy a tener que mirarlo.
En cuanto a storm drain, funciona, si te das cuenta uso el mismo código de lightingrod, pero con los parámetros que son necesarios para storm drain.
Ya, lo veo clarisimo. Es lo mismo que intenté hacer yo, pero por mas que probé la habilidad dentro del juego en batallas dobles, mi compañero se seguia viendo afectado por los movimientos tipo agua del oponente.

En mi caso para testear usé a las gemelas de la Ruta 104. Les dí a las dos 2 Totodile de Nivel 5 y modifiqué el learnset de Totodile para que su unico movimiento fuera Burbuja.
A mi Torchic le modifiqué sus 2 habilidades dandole Storm Drain. Su compañero era un Zigzagoon de la Ruta 101.
El resultado era que las gemelas le podian meter golpes a Zigzagoon normalmente pese a que Torchic tenia Storm Drain por lo cual eso no debia pasar.

No sé por qué, pero nunca lo pude hacer funcionar, y lo he estado intentando desde hace un par de dias, lol. Mas tarde probaré tu implementación, a ver si va.
 

Lumbreon

Soy nuevo XD :3
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Pues tienes tú razón. No funciona nada, nada bien en combates dobles, jajaja.
https://streamable.com/mb46a

Voy a tener que mirarlo.
No se... Mi manera funciona correctamentehttps://streamable.com/ggf5c creo que deberías usarla :|
Lo que pasa es que para que funcione tienes que cambiar activamente el objetivo haciendo un loop, que haga daño y posteriormente verifique si el siguiente objetivo tiene que recibir el daño(sí este está dormido).
Ya, lo veo clarisimo. Es lo mismo que intenté hacer yo, pero por mas que probé la habilidad dentro del juego en batallas dobles, mi compañero se seguia viendo afectado por los movimientos tipo agua del oponente.

En mi caso para testear usé a las gemelas de la Ruta 104. Les dí a las dos 2 Totodile de Nivel 5 y modifiqué el learnset de Totodile para que su unico movimiento fuera Burbuja.
A mi Torchic le modifiqué sus 2 habilidades dandole Storm Drain. Su compañero era un Zigzagoon de la Ruta 101.
El resultado era que las gemelas le podian meter golpes a Zigzagoon normalmente pese a que Torchic tenia Storm Drain por lo cual eso no debia pasar.

No sé por qué, pero nunca lo pude hacer funcionar, y lo he estado intentando desde hace un par de dias, lol. Mas tarde probaré tu implementación, a ver si va.
Ya veo...
En efecto, mi método tampoco funciona jajaja :v
O... bueno, funcionaba... Ahora si que lo hace, también había que hacer una pequeña modificación en "src/battle/battle_2.c" la cual es la siguiente:
Código:
Busca "LIGHTNING_ROD" y veras esto:
else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
             && gSideTimers[side].followmeTimer == 0
             && (gBattleMoves[gCurrentMove].power != 0
                 || gBattleMoves[gCurrentMove].target != MOVE_TARGET_x10)
             && gBattleMons[ewram16010arr(gBankAttacker)].ability != ABILITY_LIGHTNING_ROD
             && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC)
    {
        side = GetBattlerSide(gBankAttacker);
        for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
        {
            if (side != GetBattlerSide(gActiveBattler)
                && ewram16010arr(gBankAttacker) != gActiveBattler
                && gBattleMons[gActiveBattler].ability == ABILITY_LIGHTNING_ROD
                && BankGetTurnOrder(gActiveBattler) < var)
            {
/////////////////////////////////////////////////////////
Se cambia por esto:
else if (((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
             && gSideTimers[side].followmeTimer == 0
             && (gBattleMoves[gCurrentMove].power != 0
                 || gBattleMoves[gCurrentMove].target != MOVE_TARGET_x10))
             && ((gBattleMons[ewram16010arr(gBankAttacker)].ability != ABILITY_LIGHTNING_ROD
             && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) 
			 || (gBattleMons[ewram16010arr(gBankAttacker)].ability != ABILITY_STORM_DRAIN
             && gBattleMoves[gCurrentMove].type == TYPE_WATER)))
    {
        side = GetBattlerSide(gBankAttacker);
        for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
        {
            if (side != GetBattlerSide(gActiveBattler)
                && ewram16010arr(gBankAttacker) != gActiveBattler
                && (gBattleMons[gActiveBattler].ability == ABILITY_LIGHTNING_ROD 
				|| gBattleMons[gActiveBattler].ability == ABILITY_STORM_DRAIN)
                && BankGetTurnOrder(gActiveBattler) < var)
            {

Y ya está.

Ahora sí que funciona correctamente.

No, aún no lo hace, no toma ataques de más de un objetivo,funciona con water gun, o hydro pump, pero no con bubble o surf por ejemplo.
 

Lunos

Enfrentando a La Organización
Miembro insignia
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Ahora sí, con respecto a Bad Dreams, Tengo la solución.
Lo que hice(Guíandome más que todo del battle engine de dizzyegg) fue mover el código para que se active al final de cada turno, los cambios son estos.
Código:
bool32 IsBattlerAlive(u8 battlerId) // esto lo pegan en cualquier sitio
{
    if (gBattleMons[battlerId].hp == 0)
        return FALSE;
    else if (battlerId >= gBattlersCount)
        return FALSE;
    else if (gAbsentBattlerFlags & gBitTable[battlerId])
        return FALSE;
	else
		return TRUE;
}
en la función "atk80_manipulatedamage"
Código:
{
    switch (T2_READ_8(gBattlescriptCurrInstr + 1))
    {
    case 0:
        gBattleMoveDamage *= -1;
        break;
    case 1:
        gBattleMoveDamage /= 2;
        if (gBattleMoveDamage == 0)
            gBattleMoveDamage = 1;
        if ((gBattleMons[gBankTarget].maxHP / 2) < gBattleMoveDamage)
            gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2;
        break;
    case 2:
        gBattleMoveDamage *= 2;
        break;
	case 3:
	gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 8;
        if (gBattleMoveDamage == 0)
            gBattleMoveDamage = 1;
        break;
    }

    gBattlescriptCurrInstr += 2;
}
//Aquí solo agregamos el "case 3" pero si quieren reemplazan toda la función original por esta
En sitios varios
Código:
static void atkf8_trygetbaddreamstarget(void);//en cualquier sitio al principio del archivo

en "gBattleScriptingCommandsTable"
añadimos otra entrada a la tabla despues de:
atkF7_finishturn,
atkf8_trygetbaddreamstarge,//la nueva entrada es esta

y luego al final del archivo, la función que hace la magía:
static void atkf8_trygetbaddreamstarge(void)
{
    u8 badDreamsMonSide = GetBattlerSide(gBankAttacker);
	for (;gBankTarget < gBattlersCount; gBankTarget++)
    {
        if (GetBattlerSide(gBankTarget) == badDreamsMonSide)
            continue;
        if (gBattleMons[gBankTarget].status1 & STATUS_SLEEP && IsBattlerAlive(gBankTarget))
            break;
    }

    if (gBankTarget >= gBattlersCount)
        gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
    else
        gBattlescriptCurrInstr += 5;
}
buscamos "trainerslideout"
seleccionamos toda la macro y la reemplazamos por esto:
Código:
.macro trygetbaddreamstarget address
	.byte 0xf8
	.4byte \address
	.endm
	
	.macro trainerslideout bank
	.byte 0xf9
	.byte \bank
	.endm
Esto lo explicaré un poco(muy poco):
Lo que hacemos es crear una macro que se puede usar a la hora de scriptear scripts de batalla.
En la macro que buscamos lo único que se altera es su valor, ya que por alguna razón tiene que quedar de última.
y en la macro que creamos es la que ejecutaremos con la función que se coloca en src/battle/battle_4.c
Borramos la funcion o "case" de bad dreams creado con el método de Lunos y pegamos este en despues de el "case" de la habilidad "Rain Dish"
Código:
case ABILITY_BAD_DREAMS:
                if (gBattleMons[BATTLE_OPPOSITE(bank)].status1 & STATUS_SLEEP || gBattleMons[BATTLE_OPPOSITE(bank)].status1 & STATUS_SLEEP)
                {
                    BattleScriptPushCursorAndCallback(BattleScript_BadDreamsDmg);
                    effect++;
                }
                break;
Por ultimo en "data/battle_scripts_1.s" Reemplazamos el Script de bad dreams(este: BattleScript_BadDreamsDmg) por este
Código:
BattleScript_BadDreamsDmg::
	setbyte gBankTarget, 0
BattleScript_BadDreamsLoop:
	trygetbaddreamstarget BattleScript_BadDreamsEnd
	manipulatedamage 3
	orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000
	printstring BATTLE_TEXT_BadDreamsDmg
	waitmessage 0x40
	healthbarupdate TARGET
	datahpupdate TARGET
	tryfaintmon TARGET, FALSE, NULL
	atk24 BattleScript_BadDreamsIncrement
BattleScript_BadDreamsIncrement:
	addbyte gBankTarget, 1
	goto BattleScript_BadDreamsLoop
BattleScript_BadDreamsEnd::
	end3
Y si no me salté nada ya estaría.
Pues le estoy dando el intento, pero no está saliendo esto muy bien xD
https://streamable.com/xv9xk

Si corrijo el error ortografico y completo la palabra "target" en las instancias donde pusiste "atkF8_trygetbaddreamstarge", igual acabo teniendo el mismo error, lol.


Quizá es cosa mia y me salté algun paso, asi que pido disculpas de antemano. No estoy muy lucido hoy, la verdad xd ...
 

Lumbreon

Soy nuevo XD :3
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Pues le estoy dando el intento, pero no está saliendo esto muy bien xD
https://streamable.com/xv9xk

Si corrijo el error ortografico y completo la palabra "target" en las instancias donde pusiste "atkF8_trygetbaddreamstarge", igual acabo teniendo el mismo error, lol.


Quizá es cosa mia y me salté algun paso, asi que pido disculpas de antemano. No estoy muy lucido hoy, la verdad xd ...
Creo yo que no te saltaste nada, lo que pasa es que al final del archivo battle_útil tienes " atk_f8" y en los demás sitios tienes "atk_F8" y los títulos de las funciones no pueden diferir en mayúsculas o minúsculas porque interpreta que estas definiendo o apuntando a una función diferente.
 
Última edición:

Lunos

Enfrentando a La Organización
Miembro insignia
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Creo yo que no te saltaste nada, lo que pasa es que al final del archivo battle_útil tienes " atk_f8" y en los demás sitios tienes "atk_F8" y los títulos de las funciones no pueden diferir en mayúsculas o minúsculas porque interpreta que estas definiendo o apuntando a una función diferente.
Pues solucionado ese error, no parece que tu implementación esté funcionando bien tampoco xD ...
Te faltó incluir algun paso en tu post, o testear la habilidad mas a fondo.

https://streamable.com/f987g
Observaciones:
1) La habilidad no se está activando al final del primer turno, pese a que uno de los dos oponentes está dormido.
2) En el segundo turno la habilidad se activo, pero el texto se incorrecto (utiliza la habilidad de Lotad y no la de Torchic) y no se activó al final del turno, si no que se activó entre medio.
3) Al tercer turno lo dejé pasar para ver si la habilidad se seguia activando, pero en el cuarto usé Spore para dormir a Seedot, y la habilidad nunca se activó contra él.

Estamos teniendo problemas bastante similares. La diferencia es que tu implementación bebe de funciones originales y consume mas espacio en la ROM que la mia :p

;_; .... Me cago en Game Freak y en las batallas dobles. Nunca me gustaron.
 

Lumbreon

Soy nuevo XD :3
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Pues solucionado ese error, no parece que tu implementación esté funcionando bien tampoco xD ...
Te faltó incluir algun paso en tu post, o testear la habilidad mas a fondo.

https://streamable.com/f987g
Observaciones:
1) La habilidad no se está activando al final del primer turno, pese a que uno de los dos oponentes está dormido.
2) En el segundo turno la habilidad se activo, pero el texto se incorrecto (utiliza la habilidad de Lotad y no la de Torchic) y no se activó al final del turno, si no que se activó entre medio.
3) Al tercer turno lo dejé pasar para ver si la habilidad se seguia activando, pero en el cuarto usé Spore para dormir a Seedot, y la habilidad nunca se activó contra él.

Estamos teniendo problemas bastante similares. La diferencia es que tu implementación bebe de funciones originales y consume mas espacio en la ROM que la mia :p

;_; .... Me cago en Game Freak y en las batallas dobles. Nunca me gustaron.
¡Ya ví el error!

Repasando tu vídeo en el que muestras los archivos me dí cuenta de que colocaste la habilidad(case ABILITY_BAD_DREAMS:) arriba de efecto espora y abajo de irascible por lo que puedo intuir que solo reemplazaste el de tu implementación, no se sí expliqué esto pero hay que quitar la habilidad de ahí y colocarla junto con las de "end turn" osea junto con "shed skin" "rain dish" y ese tipo de habilidades.


Ahora si que si funciona, vaya por dios, lo que hubiera facilitado las cosas usar github, creo que me crearé una cuenta ahora XD.
 

Lunos

Enfrentando a La Organización
Miembro insignia
Respuesta: Re: (pokeruby) Implementando habilidades nuevas

¡Ya ví el error!

Repasando tu vídeo en el que muestras los archivos me dí cuenta de que colocaste la habilidad(case ABILITY_BAD_DREAMS:) arriba de efecto espora y abajo de irascible por lo que puedo intuir que solo reemplazaste el de tu implementación, no se sí expliqué esto pero hay que quitar la habilidad de ahí y colocarla junto con las de "end turn" osea junto con "shed skin" "rain dish" y ese tipo de habilidades.


Ahora si que si funciona, vaya por dios, lo que hubiera facilitado las cosas usar github, creo que me crearé una cuenta ahora XD.
Puees.. me sigue sin ir.
Al principio me daba error al compilar porque soy tonto y olvidé corregir "targe", que asi aparece en tu post.
Pero pese a que logré que compìlara, a la hora de probar la habilidad puees.. no funciona.
https://streamable.com/dgzza

Antes de enviar este post decidí borrar mi partida guardada y empezar de 0 yendo lo mas rapido posible al mismo punto para probar de vuelta, pero nada, no va.

-En batallas individuales, el texto de Bad Dreams menciona a la habilidad del oponente, cuando deberia estar mencionando la del pokémon con Bad Dreams.
-Voy con las gemelas de la Ruta 104. Mi Torchic tiene Bad Dreams, uso Spore en el primer turno para dormir a Seedot que es el oponente en el lado izquierdo, finaliza el primer turno y.... no pasa nada.


EDITO: Probablemente aquí metí la pata de forma muy gorda, poniendo el efecto debajo de case ABILITY_TRUANT.
InmortalKaktus me dedicó un huevo de horas ayudandome con un par de asuntos, entre ellos corregir mi implementación de Bad Dreams que ya la posteó él al final de este tema. Decidí dejar este relato sobre el asunto para dejar en claro que los problemas presentados en este post los cuales ya subrayé, fueron culpa mia.
Ya todo está solucionado.
 
Última edición:

Kaktus

Miembro insignia
Miembro insignia
Respuesta: (pokeruby) Implementando habilidades nuevas

¡Buenas!

Viendo que os estaba costando tanto el tema de Bad Dreams me he puesto un ratito a hacerlo todo desde cero y he conseguido que funcione tanto en individuales como en dobles, aquí dos GIF's que lo demuestran (en los siguientes turnos funciona también correctamente)


Bien, una vez demostrado que funciona, paso a dejar el BattleScript (que es muy importante) y la función.

En "data/battle_scripts_1.s" añadiremos

Código:
BattleScript_BadDreamsActivates:: @ 81D8C43
	healthbarupdate USER
	datahpupdate USER
	printstring BATTLE_TEXT_HurtOther
	waitmessage 64
	end3
Y en "src/battle/battle_util.c" añadiremos al principio del archivo

Código:
extern u8 BattleScript_BadDreamsActivates[];
Entre los demás de su tipo


Y luego, muy importante donde colocamos esto, si no, no funcionará.

Debe estar dentro del "case ABILITYEFFECT_ENDTURN:", esta función

Código:
case ABILITY_BAD_DREAMS:
    if ((gBattleMons[gBankAttacker].status1 & STATUS_SLEEP) && gBattleMons[gBankAttacker].hp != 0)
    {
        gLastUsedAbility = ABILITY_BAD_DREAMS;
        BattleScriptPushCursorAndCallback(BattleScript_BadDreamsActivates);
        gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 8;
        if (gBattleMoveDamage == 0)
            gBattleMoveDamage = 1;
        effect++;
    }
    break;

Sabéis que antes de todo esto hay que definir la habilidad



Definir su nombre in-game



Y su descripción



¡Espero que os sirva para futuras habilidades! ;)
 
Arriba