(pokeruby) Implementando habilidades nuevas

Avisos


Like Tree37Gracias
Respuesta
 
Herramientas Desplegado
  #1  
28/03/2019
Predeterminado (pokeruby) Implementando habilidades nuevas
¡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.

Spoiler



Asi que vamos por partes...

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

Paso 1

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".


Paso 2

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.


Paso 3

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

Audaz,Experto,Adaptable

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 por Lumbreon; 13/05/2019 a las 02:48
  #2  
28/03/2019
Predeterminado 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 por Lunos; 20/04/2019 a las 00:12 Razón: Correcciones, aclaraciones y eliminada la implementación de Unburden pues está mal hecha, o más bien a mitad de camino.
  #3  
29/03/2019
Predeterminado 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: Lumbreon

  #4  
01/04/2019
Predeterminado Respuesta: (pokeruby) Implementando habilidades nuevas
Dicho por FatKip Ver mensaje
¡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.

Normalidad/Normalize

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.

Actualización de Sturdy/Robustez

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".
  #5  
06/04/2019
Corazón Re: Respuesta: (pokeruby) Implementando habilidades nuevas
Dicho por Lumbreon Ver mensaje

"Aftermath"

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:
Dicho por Lumbreon Ver mensaje

"Anger Point"

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.
Gracias: Lumbreon

Última edición por Lunos; 06/04/2019 a las 18:35
  #6  
12/04/2019
Predeterminado 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.

Encadenado

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.


Scrappy o Intrepido

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;
                }
Gracias: Tyren Sealess
  #7  
16/04/2019
Predeterminado 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.
Gracias: Lumbreon

Última edición por Lunos; 19/04/2019 a las 21:50
  #8  
24/04/2019
Predeterminado Respuesta: Re: (pokeruby) Implementando habilidades nuevas

Spoiler

Dicho por Lunos Ver mensaje
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.

Bad Dreams


En "src/battle/battle_4.c"


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;
}

En "include/macros/battle_scripts.inc"

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

En "src/battle/battle_util.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.
Gracias: Tyren Sealess

Última edición por Lumbreon; 24/04/2019 a las 05:54
  #9  
26/04/2019
Corazón Respuesta: Re: (pokeruby) Implementando habilidades nuevas
Dicho por Lumbreon Ver mensaje
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.

Bad Dreams


En "src/battle/battle_4.c"


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;
}

En "include/macros/battle_scripts.inc"

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

En "src/battle/battle_util.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.
Gracias: Lumbreon
  #10  
26/04/2019
Predeterminado Respuesta: Re: (pokeruby) Implementando habilidades nuevas
Dicho por Lunos Ver mensaje
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:

Storm Drain

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).
Gracias: Lunos

Última edición por Lumbreon; 26/04/2019 a las 02:45 Razón: vengaza xd
Respuesta

Herramientas
Desplegado

Permisos para publicar mensajes
No puedes crear nuevos temas
No puedes responder mensajes
No puedes subir archivos adjuntos
No puedes editar tus mensajes

Los BB code están Activado
Los Emoticones están Activado
El código [IMG] está Activado
El Código HTML está Desactivado
Trackbacks are Activado
Pingbacks are Activado
Refbacks are Desactivado



Extra
Estilo clásico
La franja horaria es GMT +1. Ahora son las 12:35.