Registrarse

CFRU | Teracristalización/Terastal (En Proceso) (ACT-22-04-24)

AxelLoquendo

Todo terreno 👻
Hola, no se donde más poner esto pero necesito ayuda, estoy re creando la teracristalización y más o menos tengo la idea para poder trabajar en el cfru.

¿Qué es la teracristalización?
Permite transformar a los Pokémon a ejemplares cristalizados cambiando así, de forma momentánea, el Tipo que tienen.

¿ Qué es la escala teracristal?
Es una escala de niveles para medir la fuerza de un Pokémon teracristalizado. Cuanto mayor sea su escala, más fuerte será su efecto en el combate. En el juego original, los entrenadores ganan puntos de escala al ganar batallas. Estos puntos se suman y determinan la escala de cada entrenador.

Empezamos con la planificación.

Primero debemos tener en cuenta que necesitamos crear la escala teracristal.

Mi idea es crearla en "battle_util.c" ya que según creo yo, este archivo contiene la mayoría de la lógica de batalla. Aquí deberíamos agregar una función para añadir puntos a la escala teracristalizada, esto debería permitir añadir los puntos en el momento adecuado de la batalla.

También debemos agregar una nueva declaración de tipo "struct" a este lo podríamos llamar "scale" y seguido debemos de agregar los campos que sean necesarios como por ejemplo: "scale_id", "scale_points" y "scale_level"

Luego debemos de crear una función que se encargue de crear y ajustar una nueva instancia de "scale", luego usar algún método de "update" que se llamará cada vez que algo cambie en la batalla. Ahora necesitaremos agregar la lógica necesaria para actualizar la escala teracristalizada en función a los cambios que podrían ocurrir en batalla. Considerando eventos relevantes, como el retiro de un PKMN y la victoria de un entrenador. Cuando algún evento relevante ocurra debemos actualizar la escala usando el valor de los campos del "scale" que correspondan al evento, permitiendo así que la escala teracristalizada se mantenga actualizada durante todo el combate.

Si alguien tiene idea de como y en que archivos ir agregando la, se lo agradecería mucho, yo estaré actualizando el proceso.

ACT-30-12-23
ok, estuve un tiempo fuera pero es por que estaba tratando de hacer la teracristalización, estuve prueba y error, y aunque nunca hice funcionar mi código (excepto que una vez si lo hice pero sin trigger y solo se activaba si el pkmn usaba un ataque del mismo tipo que su teratipo)

dejare mi codigo que no funciona aquí, por si alguien quiere ayudar y se toma el tiempo de ver mi codigo.

#include "defines.h"
#include "defines_battle.h"
#include "../include/battle_anim.h"
#include "../include/pokemon_summary_screen.h"
#include "../include/constants/items.h"
#include "../include/constants/pokedex.h"
#include "../include/constants/trainer_classes.h"

#include "../include/new/battle_indicators.h"
#include "../include/new/battle_util.h"
#include "../include/new/terastallized.h"
#include "../include/new/form_change.h"
#include "../include/new/frontier.h"
#include "../include/new/general_bs_commands.h"
#include "../include/new/item.h"
#include "../include/new/mega.h"
#include "../include/new/mega_battle_scripts.h"
#include "../include/new/util.h"

#define TRAINER_ITEM_COUNT 4

//This file's functions:
static bool8 IsBannedHeldItemForTerastallized(u16 item);
static const u8* DoTerastallized(u8 bank);
static const u8* DoTerastal(u8 bank);
static bool8 IsItemTeraOrb(u16 item);
static item_t FindTrainerTeraOrb(u16 trainerId);
static item_t FindPlayerTeraOrb(void);
static item_t FindBankTeraOrb(u8 bank);

static const item_t sTeraOrbTable[] =
{
ITEM_TERA_ORB,
};

struct TerastalMove
{
u16 species;
u8 moveType;
u16 terastalMove;
};

static const struct TerastalMove sTerastalMoveTable[] =
{
{SPECIES_TERAPAGOS_STELLAR_FORM, TYPE_STELLAR, MOVE_TERABLAST},
};

species_t GetTerastallizedSpecies(unusedArg u8 bank, unusedArg bool8 checkTerastalInstead)
{
#ifndef TERASTALLIZED_FEATURE
return SPECIES_NONE;
#else
u16 species = SPECIES(bank); //Prevents ditto too

if (IsBannedHeldItemForTerastallized(ITEM(bank)))
return SPECIES_NONE;

if (!checkTerastalInstead) //Checking regular Terastallized
{
return SPECIES_NONE; //Certain Pokemon can't Terastallized

return species; //Returning the species of the Pokemon is an indicator that they can Terastallized
}
else //Check Terastal
{
struct Pokemon* mon = GetBankPartyData(bank);
return GetTerastalSpecies(mon->species, mon->Terastal);
}

return SPECIES_NONE;
#endif
}

static bool8 IsBannedHeldItemForTerastallized(u16 item)
{
if (IsMegaZMoveBannedBattle())
return FALSE; //These items have no effect so don't ban them

return IsMegaStone(item)
|| IsZCrystal(item)
|| IsPrimalOrb(item);
}

bool8 CanTerastallized(u8 bank)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED && !gNewBS->terastallizedData.used[bank])
return GetTeratallizedSpecies(bank, FALSE) != SPECIES_NONE;

return FALSE;
}

bool8 CanTerastal(u8 bank)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED && !gNewBS->terastallizedData.used[bank])
return GetTerastallizedSpecies(bank, TRUE) != SPECIES_NONE;

return FALSE;
}

static const u8* DoTerastallized(u8 bank)
{
u16 terastallizedSpecies = GetTerastallizedSpecies(bank, FALSE);

if (terastallizedSpecies == SPECIES_NONE) //Can't Terastallized
return NULL;

gBattleScripting.bank = bank;
gLastUsedItem = FindBankTeraOrb(bank);

u8 newType = GetTerastallizedNewType(terastallizedSpecies, moveType);

gBattleMons[bank].type1 = newType;
gBattleMons[bank].type2 = newType;

if (moveType == MOVE_TERABLAST) {
gBattleMons[bank].ppBonuses = newType;

return BattleScript_Terastallized;
}

static const u8* DoTerastal(u8 bank)
{
u16 terastalSpecies = GetTerastallizedSpecies(bank, TRUE);

if (terastalSpecies == SPECIES_NONE) //Can't Terastal
return NULL;

DoFormChange(bank, terastalSpecies, FALSE, FALSE, FALSE);

gBattleScripting.bank = bank;
gLastUsedItem = FindBankTeraOrb(bank);
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, terastalSpecies);

return BattleScript_Terastallized;
}

const u8* GetTerastallizedScript(u8 bank)
{
const u8* script = DoTerastal(bank);
if (script != NULL)
return script;

return DoTerastallized(bank);
}

void TerastalRevert(struct Pokemon* party)
{
u32 i;

for (i = 0; i < PARTY_SIZE; ++i)
TryRevertTerastal(&party);
}

void TryRevertTerastal(struct Pokemon* mon)
{
u16 baseSpecies = GetTerastalBaseForm(mon->species);

if (baseSpecies != SPECIES_NONE)
{
mon->species = baseSpecies;
mon->terastal = TRUE; //If encountered in the wild, now can permanently Terastal
CalculateMonStats(mon);
}
}

void TryRevertBankTerastal(u8 bank)
{
struct Pokemon* mon = GetBankPartyData(bank);
u16 baseSpecies = GetTerastalBaseForm(GetMonData(mon, MON_DATA_SPECIES, NULL));

if (baseSpecies != SPECIES_NONE) //Bank is terastallized - can't check timer because already reset
{
if (mon->backupSpecies != SPECIES_NONE)
baseSpecies = mon->backupSpecies;

DoFormChange(bank, baseSpecies, FALSE, FALSE, FALSE);
mon->terastal = TRUE; //If encountered in the wild, now can permanently Terastal
}
}

u16 GetTerastalSpecies(u16 species, bool8 canTerastal)
{
u32 i;
const struct Evolution* evolutions = gEvolutionTable[species];

if (canTerastal) //Mon can Terastal
{
for (i = 0; i < EVOS_PER_MON; ++i)
{
if (evolutions.method == EVO_NONE) //Most likely end of entries
break; //Break now to save time
else if (evolutions.method == EVO_TERASTAL)
{
//Ignore reversion information
if (evolutions.param == 0) continue;

//Any value other than 0 indicates Tera potential
return evolutions.targetSpecies;
}
}
}

return SPECIES_NONE;
}

u16 GetTerastalBaseForm(u16 species)
{
const struct Evolution* evolutions = gEvolutionTable[species];

for (u8 i = 0; i < EVOS_PER_MON; ++i)
{
if (evolutions.method == EVO_NONE) //Most likely end of entries
break; //Break now to save time
else if (evolutions.method == EVO_TERASTAL && evolutions.param == 0)
return evolutions.targetSpecies;
}

return SPECIES_NONE;
}

static bool8 IsItemTeraOrb(u16 item)
{
for (u8 i = 0; i < ARRAY_COUNT(sTeraOrbTable); ++i)
{
if (item == sTeraOrbTable)
return TRUE;
}

return FALSE;
}

static item_t FindTrainerTeraOrb(u16 trainerId)
{
if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK) || IsFrontierTrainerId(trainerId))
return ITEM_TERA_ORB;

for (u8 i = 0; i < TRAINER_ITEM_COUNT; ++i)
{
if (IsItemTeraOrb(gTrainers[trainerId].items))
return gTrainers[trainerId].items;
}

return ITEM_NONE;
}

static item_t FindPlayerTeraOrb(void)
{
if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK))
return ITEM_TERA_ORB;

#if (defined UNBOUND && defined VAR_KEYSTONE) //Mega Ring doubles as Tera Orb in Unbound
u16 teraorb = VarGet(VAR_KEYSTONE);
if (teraorb != ITEM_NONE)
return teraorb;
#else
for (u8 i = 0; i < ARRAY_COUNT(sTeraOrbTable); ++i)
{
if (CheckBagHasItem(sTeraOrbTable, 1))
return sTeraOrbTable;
}
#endif

#ifdef DEBUG_TERASTALLIZED
return ITEM_TERA_ORB; //Give player Tera Orb if they have none
#endif

return ITEM_NONE;
}

static item_t FindBankTeraOrb(u8 bank)
{
#ifdef DEBUG_TERASTALLIZED
if (bank + 1)
return ITEM_TERA_ORB;
#endif

if (SIDE(bank) == SIDE_OPPONENT)
{
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
if (GetBattlerPosition(bank) == B_POSITION_OPPONENT_LEFT)
return FindTrainerTeraOrb(gTrainerBattleOpponent_A);
else
return FindTrainerTeraOrb(SECOND_OPPONENT);
}
else
return FindTrainerTeraOrb(gTrainerBattleOpponent_A);
}
else //SIDE_PLAYER
{
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
if (GetBattlerPosition(bank) == B_POSITION_PLAYER_RIGHT)
return FindTrainerTeraOrb(VarGet(VAR_PARTNER));
else
return FindPlayerTeraOrb();
}
else
return FindPlayerTeraOrb();
}
}

bool8 TerastallizedEnabled(u8 bank)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED)
{
if (FindBankTeraOrb(bank) == ITEM_NONE)
{
#ifdef DEBUG_TERASTALLIZED
return TRUE;
#else
return FALSE;
#endif
}

return TRUE;
}

return FALSE;
}

bool8 HasBankTerastallizedAlready(u8 bank)
{
if ((SIDE(bank) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|| (SIDE(bank) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))
{
return gNewBS->terastallizedData.used[bank];
}

return gNewBS->terastallizedData.used[bank]
|| (IS_DOUBLE_BATTLE && gNewBS->terastallizedData.used[PARTNER(bank)]);
}

bool8 IsTerastalSpecies(u16 species)
{
const struct Evolution* evolutions = gEvolutionTable[species];

for (u8 i = 0; i < EVOS_PER_MON; ++i)
{
if (evolutions.method == EVO_NONE) //Most likely end of entries
break; //Break now to save time
else if (evolutions.method == EVO_TERASTAL && evolutions.param == FALSE)
return TRUE;
}

return FALSE;
}

bool8 IsTerastallized(u8 bank)
{
return gNewBS->terastallizedData.timer[bank] != 0;
}

bool8 IsTerastal(u8 bank)
{
return IsTerastalSpecies(GetBankPartyData(bank)->species);
}

bool8 HasTerastallizedSymbol(u8 bank)
{
return IsTerastallized(bank) || IsTerastallized(bank);
}

bool8 DoesTeratallizedUsageStopMegaEvolution(u8 bank)
{
return gNewBS->terastallizedData.used[bank]
&& gNewBS->terastallizedData.partyIndex[SIDE(bank)] & gBitTable[gBattlerPartyIndexes[bank]];
}

bool8 MonCanTerastallized(struct Pokemon* mon)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED)
{
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
u16 item = GetMonData(mon, MON_DATA_HELD_ITEM, NULL);

if (IsBannedTerastallizedSpecies(species)
|| IsBannedHeldItemForTerastallized(item))
return FALSE;

return TRUE;
}

return FALSE;
}

bool8 PlayerHasNoMonsLeftThatCanTerastallized(void)
{
u8 i, firstMonId, lastMonId;
struct Pokemon* party = LoadPartyRange(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), &firstMonId, &lastMonId);

for (i = firstMonId; i < lastMonId; ++i)
{
if (MON_CAN_BATTLE(&party)
&& MonCanTerastallized(&party))
return FALSE;
}

return TRUE;
}

void TryFadeBankPaletteForTerastallized(u8 bank, u16 paletteOffset)
{
if (IsTerastallized(bank)
{
u8 newType = GetTerastallizedNewType(SPECIES(bank), MOVE_TERABLAST);

switch (newType)
{
case TYPE_NORMAL:
BlendPalette(paletteOffset, 16, 4, RGB(190, 190, 190)); // Normal - Gris claro
break;
case TYPE_FIRE:
BlendPalette(paletteOffset, 16, 4, RGB(255, 69, 0)); // Fire - Rojo
break;
case TYPE_WATER:
BlendPalette(paletteOffset, 16, 4, RGB(0, 0, 255)); // Water - Azul
break;
case TYPE_GRASS:
BlendPalette(paletteOffset, 16, 4, RGB(0, 128, 0)); // Grass - Verde oscuro
break;
case TYPE_ELECTRIC:
BlendPalette(paletteOffset, 16, 4, RGB(255, 255, 0)); // Electric - Amarillo
break;
case TYPE_ICE:
BlendPalette(paletteOffset, 16, 4, RGB(173, 216, 230)); // Ice - Azul claro
break;
case TYPE_FIGHTING:
BlendPalette(paletteOffset, 16, 4, RGB(128, 0, 0)); // Fighting - Marrón oscuro
break;
case TYPE_POISON:
BlendPalette(paletteOffset, 16, 4, RGB(128, 0, 128)); // Poison - Morado oscuro
break;
case TYPE_GROUND:
BlendPalette(paletteOffset, 16, 4, RGB(139, 69, 19)); // Ground - Marrón
break;
case TYPE_FLYING:
BlendPalette(paletteOffset, 16, 4, RGB(135, 206, 250)); // Flying - Azul claro
break;
case TYPE_PSYCHIC:
BlendPalette(paletteOffset, 16, 4, RGB(255, 0, 255)); // Psychic - Magenta
break;
case TYPE_BUG:
BlendPalette(paletteOffset, 16, 4, RGB(34, 139, 34)); // Bug - Verde
break;
case TYPE_ROCK:
BlendPalette(paletteOffset, 16, 4, RGB(139, 69, 19)); // Rock - Marrón
break;
case TYPE_GHOST:
BlendPalette(paletteOffset, 16, 4, RGB(123, 104, 238)); // Ghost - Azul violeta
break;
case TYPE_DRAGON:
BlendPalette(paletteOffset, 16, 4, RGB(106, 90, 205)); // Dragon - Azul pálido
break;
case TYPE_DARK:
BlendPalette(paletteOffset, 16, 4, RGB(0, 0, 0)); // Dark - Negro
break;
case TYPE_STEEL:
BlendPalette(paletteOffset, 16, 4, RGB(192, 192, 192)); // Steel - Plata
break;
case TYPE_FAIRY:
BlendPalette(paletteOffset, 16, 4, RGB(255, 182, 193)); // Fairy - Rosa claro
case TYPE_STELLAR:
BlendPalette(paletteOffset, 16, 4, RGB(255, 255, 255)); // Stellar - Blanco claro
break

#ifdef NATIONAL_DEX_CALYREX
if (SpeciesToNationalPokedexNum(SPECIES(bank)) == NATIONAL_DEX_CALYREX)
BlendPalette(paletteOffset, 16, 4, RGB(0, 5, 31)); //Terastallized Blue
else
#endif
BlendPalette(paletteOffset, 16, 4, RGB(31, 0, 12)); //Terastallized Pinkish-Red

CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, 32);
}
}

void EndBattleTerastallizedRevert(u8 bank)
{
if (BATTLER_ALIVE(bank) && IsTerastallized(bank))
{
u16 hp, maxHP;
struct Pokemon* mon = GetBankPartyData(bank);

hp = GetBaseCurrentHP(bank);
maxHP = GetBaseMaxHP(bank);
SetMonData(mon, MON_DATA_HP, &hp);
SetMonData(mon, MON_DATA_MAX_HP, &maxHP);
gNewBS->terastallizedData.timer[bank] = 0;
}
}

//Called from Battle Script
void ClearBallAnimActiveBit(void)
{
gBattleSpritesDataPtr->healthBoxesData[gBattleScripting.bank].ballAnimActive = FALSE;
}

#include "../include/teratype.h"

struct EspeciesYTipos {
u16 especie;
u8 tipos[2]; // Cambia a 3 si permites más de un tipo
};

u8 GetTerastallizedNewType(void) {
static const u8 tiposDisponibles[] = {TYPE_NORMAL, TYPE_FIGHTING, TYPE_FLYING, TYPE_POISON, TYPE_GROUND, TYPE_ROCK, TYPE_BUG, TYPE_GHOST, TYPE_STEEL, TYPE_FIRE, TYPE_WATER, TYPE_GRASS, TYPE_ELECTRIC, TYPE_PSYCHIC, TYPE_ICE, TYPE_DRAGON, TYPE_DARK, TYPE_FAIRY, TYPE_STELLAR};
}

static const struct SpeciesYTypes speciesYTypes[] = {
{SPECIES_CHARIZARD, {TYPE_FIRE, TYPE_DRAGON}},
{SPECIES_BLASTOISE, {TYPE_WATER}},
// Agrega más especies y sus tipos según sea necesario
};

u8 GetTerastallizedNewType(u16 specie, u8 moveType) {
// Buscar la especie en la lista y verificar si el tipo del ataque coincide con alguno de los tipos de la especie
for (u8 i = 0; i < ARRAY_COUNT(speciesYTypes); ++i) {
if (speciesYTypes.specie == specie) {
if (speciesYTypes.types[0] == moveType || speciesYTypes.types[1] == moveType) {
// Si el tipo del ataque coincide con uno de los tipos de la especie, devolver ese tipo
return moveType;
} else {
// Si no coincide, devolver el primer tipo de la especie
return speciesYTypes.types[0];
}
}
}

// Si no se encuentra la especie, devolver un tipo predeterminado (Tipo Normal, por ejemplo)
return TYPE_NORMAL;
}


psdt:
solo dejo el codigo de la tera mas la base de datos donde iba a almacenar todos los pokemons con sus respectivos teratipos..

psdt2:
también dejo el trigger que iba a usar, el cual hice en 5 minutos xD

Tera_Trigger.png


ACT-20-04-2024
Aun no me rindo, ya voy por el intento 342 >:c
terastal.c - Dev-C++ 20_04_2024 10_26_45 p.m..png

ACT-22-04-2024
Poco a poco va quedando la teracristalización, pero antes de ir de lleno a la mecánica decidí poner los teratipos y mostrarlo como 3er tipo en la sunmary screen, puse que los teratipos sean aleatorios en pokemons salvajes y regalados como los iniciales.

ahora si, iré con todo con la mecánica.
Teratype test.png
 

Adjuntos

Última edición:

Erkey830

Fuck off!
No tengo la menor idea de como aplicarlo pero supongo e imagino que podrias imitar una dinamax o una mega que hace el "cambio de forma" en combate, o mirar en decomp si te sirve como una guia de como estan haciendolo ellos
 

AxelLoquendo

Todo terreno 👻
Act-08-12-23
Investigación Teracristalización-CFRU


¿Qué es la teracristalización?
Permite transformar a los Pokémon a ejemplares cristalizados cambiando así, de forma momentánea, el Tipo que tienen.

¿ Qué es la escala teracristal?
Es una escala de niveles para medir la fuerza de un Pokémon teracristalizado. Cuanto mayor sea su escala, más fuerte será su efecto en el combate. En el juego original, los entrenadores ganan puntos de escala al ganar batallas. Estos puntos se suman y determinan la escala de cada entrenador.

Empezamos con la planificación.

Primero debemos tener en cuenta que necesitamos crear la escala teracristal.

Mi idea es crearla en "battle_util.c" ya que según creo yo, este archivo contiene la mayoría de la lógica de batalla. Aquí deberíamos agregar una función para añadir puntos a la escala teracristalizada, esto debería permitir añadir los puntos en el momento adecuado de la batalla.

También debemos agregar una nueva declaración de tipo "struct" a este lo podríamos llamar "scale" y seguido debemos de agregar los campos que sean necesarios como por ejemplo: "scale_id", "scale_points" y "scale_level"

Luego debemos de crear una función que se encargue de crear y ajustar una nueva instancia de "scale", luego usar algún método de "update" que se llamará cada vez que algo cambie en la batalla. Ahora necesitaremos agregar la lógica necesaria para actualizar la escala teracristalizada en función a los cambios que podrían ocurrir en batalla. Considerando eventos relevantes, como el retiro de un PKMN y la victoria de un entrenador. Cuando algún evento relevante ocurra debemos actualizar la escala usando el valor de los campos del "scale" que correspondan al evento, permitiendo así que la escala teracristalizada se mantenga actualizada durante todo el combate.
 

Draiii

🌙
Todo hermoso, me gustó la redacción del post y me alegra que quieras añadir esto al CFRU, si lo logras será algo impresionante. Al no saber nada de código y esas cosas solo daré una idea (quiero aclarar que hablo con inexperiencia, si no se puede pues...):

Imita la mecánica de la mega evolución, podrías cambiar el sistema que logra el cambio en el Pokémon por un sistema que cambie el tipo del Pokémon, con eso ya tendrías algo adelantando. Claramente faltarán cosas pero se pueden ir agregando.

Lo dejo ahí. Buena suerte pa'.
 

AxelLoquendo

Todo terreno 👻
Todo hermoso, me gustó la redacción del post y me alegra que quieras añadir esto al CFRU, si lo logras será algo impresionante. Al no saber nada de código y esas cosas solo daré una idea (quiero aclarar que hablo con inexperiencia, si no se puede pues...):

Imita la mecánica de la mega evolución, podrías cambiar el sistema que logra el cambio en el Pokémon por un sistema que cambie el tipo del Pokémon, con eso ya tendrías algo adelantando. Claramente faltarán cosas pero se pueden ir agregando.

Lo dejo ahí. Buena suerte pa'.
Teóricamente es la mejor opción, pero si tenemos en cuenta de que se necesita el cambio de forma para ciertas especies, como lo serian los ogerpon y el terapagos, además de que en el hipotético caso logro hacer que se cambien los tipos sin cambiar la forma del pokemon, aún queda el hecho de que terablast cambie de tipo también.

Si bien puedo hacer una secuencia de comandos donde pueda hacer que terablast cambie de tipo, por el teratipo asignado, queda el hecho de los indicadores de que la tera está ejecutada más la animación y la aura que rodee al pokemon para parecer estar cristalizado, aunque este último puedo usar parte del código de dynamax.
 

Draiii

🌙
Teóricamente es la mejor opción, pero si tenemos en cuenta de que se necesita el cambio de forma para ciertas especies, como lo serian los ogerpon y el terapagos, además de que en el hipotético caso logro hacer que se cambien los tipos sin cambiar la forma del pokemon, aún queda el hecho de que terablast cambie de tipo también.

Si bien puedo hacer una secuencia de comandos donde pueda hacer que terablast cambie de tipo, por el teratipo asignado, queda el hecho de los indicadores de que la tera está ejecutada más la animación y la aura que rodee al pokemon para parecer estar cristalizado, aunque este último puedo usar parte del código de dynamax.
Ahí te acabas de dar una solución solo. (?)
Ya sería cuestión de prueba y error.
 

AxelLoquendo

Todo terreno 👻
Act-11-12-23
En base al código de la mega evolución en el Complete-Fire-Red-Upgrade, hice ese boceto de lo que sería la teracristalización.

Estuve 3 días viendo clases de C++ y probando y creando virus ;-;

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
char nombre[50];
char tipo1[20];
char tipo2[20];
char colorAura[20];
int estadoOriginal[2];
} Pokemon;

void generarAura(Pokemon* pokemon) {
if (strcmp(pokemon->tipo1, "Fuego") == 0 || strcmp(pokemon->tipo2, "Fuego") == 0) {
strcpy(pokemon->colorAura, "Rojo");
} else if (strcmp(pokemon->tipo1, "Agua") == 0 || strcmp(pokemon->tipo2, "Agua") == 0) {
strcpy(pokemon->colorAura, "Azul");
} else if (strcmp(pokemon->tipo1, "Planta") == 0 || strcmp(pokemon->tipo2, "Planta") == 0) {
strcpy(pokemon->colorAura, "Verde");
} else {
strcpy(pokemon->colorAura, "Blanco");
}
}

void aplicarTeracristalizacion(Pokemon* pokemon) {
// Guardar el estado original del Pokémon antes de aplicar la Teracristalización
pokemon->estadoOriginal[0] = pokemon->tipos[0];
pokemon->estadoOriginal[1] = pokemon->tipos[1];

// Aplicar la Teracristalización al Pokémon
// ...
pokemon->tipos[0] = 10; // Ejemplo de modificación de tipos
pokemon->tipos[1] = 20;
}

void restaurarEstadoNormal(Pokemon* pokemon) {
// Restaurar los tipos originales del Pokémon
pokemon->tipos[0] = pokemon->estadoOriginal[0];
pokemon->tipos[1] = pokemon->estadoOriginal[1];
}

int main() {
FILE* archivo;
Pokemon pokemons[100];
int numPokemons = 0;

archivo = fopen("pokemons.txt", "r");
if (archivo == NULL) {
printf("Error al abrir el archivo.\n");
return 1;
}

while (fscanf(archivo, "%[^,], %[^,], %[^\n]\n", pokemons[numPokemons].nombre, pokemons[numPokemons].tipo1, pokemons[numPokemons].tipo2) == 3) {
generarAura(&pokemons[numPokemons]);
numPokemons++;
}

fclose(archivo);

for (int i = 0; i < numPokemons; i++) {
printf("Nombre: %s\n", pokemons.nombre);
printf("Tipo 1: %s\n", pokemons.tipo1);
printf("Tipo 2: %s\n", pokemons.tipo2);
printf("Color del Aura: %s\n", pokemons.colorAura);
printf("\n");
}

// Aplicar la Teracristalización a un Pokémon específico
aplicarTeracristalizacion(&pokemons[0]);

// Restaurar el estado normal del Pokémon
restaurarEstadoNormal(&pokemons[0]);

return 0;
}
No sé si estará bien, si alguien sabe de esto, dígame si esta bien ;-;

Psdt: ya tengo los gráficos xd
 

AxelLoquendo

Todo terreno 👻
ACT-30-12-23
ok, estuve un tiempo fuera pero es por que estaba tratando de hacer la teracristalización, estuve prueba y error, y aunque nunca hice funcionar mi código (excepto que una vez si lo hice pero sin trigger y solo se activaba si el pkmn usaba un ataque del mismo tipo que su teratipo)

dejare mi codigo que no funciona aquí, por si alguien quiere ayudar y se toma el tiempo de ver mi codigo.

#include "defines.h"
#include "defines_battle.h"
#include "../include/battle_anim.h"
#include "../include/pokemon_summary_screen.h"
#include "../include/constants/items.h"
#include "../include/constants/pokedex.h"
#include "../include/constants/trainer_classes.h"

#include "../include/new/battle_indicators.h"
#include "../include/new/battle_util.h"
#include "../include/new/terastallized.h"
#include "../include/new/form_change.h"
#include "../include/new/frontier.h"
#include "../include/new/general_bs_commands.h"
#include "../include/new/item.h"
#include "../include/new/mega.h"
#include "../include/new/mega_battle_scripts.h"
#include "../include/new/util.h"

#define TRAINER_ITEM_COUNT 4

//This file's functions:
static bool8 IsBannedHeldItemForTerastallized(u16 item);
static const u8* DoTerastallized(u8 bank);
static const u8* DoTerastal(u8 bank);
static bool8 IsItemTeraOrb(u16 item);
static item_t FindTrainerTeraOrb(u16 trainerId);
static item_t FindPlayerTeraOrb(void);
static item_t FindBankTeraOrb(u8 bank);

static const item_t sTeraOrbTable[] =
{
ITEM_TERA_ORB,
};

struct TerastalMove
{
u16 species;
u8 moveType;
u16 terastalMove;
};

static const struct TerastalMove sTerastalMoveTable[] =
{
{SPECIES_TERAPAGOS_STELLAR_FORM, TYPE_STELLAR, MOVE_TERABLAST},
};

species_t GetTerastallizedSpecies(unusedArg u8 bank, unusedArg bool8 checkTerastalInstead)
{
#ifndef TERASTALLIZED_FEATURE
return SPECIES_NONE;
#else
u16 species = SPECIES(bank); //Prevents ditto too

if (IsBannedHeldItemForTerastallized(ITEM(bank)))
return SPECIES_NONE;

if (!checkTerastalInstead) //Checking regular Terastallized
{
return SPECIES_NONE; //Certain Pokemon can't Terastallized

return species; //Returning the species of the Pokemon is an indicator that they can Terastallized
}
else //Check Terastal
{
struct Pokemon* mon = GetBankPartyData(bank);
return GetTerastalSpecies(mon->species, mon->Terastal);
}

return SPECIES_NONE;
#endif
}

static bool8 IsBannedHeldItemForTerastallized(u16 item)
{
if (IsMegaZMoveBannedBattle())
return FALSE; //These items have no effect so don't ban them

return IsMegaStone(item)
|| IsZCrystal(item)
|| IsPrimalOrb(item);
}

bool8 CanTerastallized(u8 bank)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED && !gNewBS->terastallizedData.used[bank])
return GetTeratallizedSpecies(bank, FALSE) != SPECIES_NONE;

return FALSE;
}

bool8 CanTerastal(u8 bank)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED && !gNewBS->terastallizedData.used[bank])
return GetTerastallizedSpecies(bank, TRUE) != SPECIES_NONE;

return FALSE;
}

static const u8* DoTerastallized(u8 bank)
{
u16 terastallizedSpecies = GetTerastallizedSpecies(bank, FALSE);

if (terastallizedSpecies == SPECIES_NONE) //Can't Terastallized
return NULL;

gBattleScripting.bank = bank;
gLastUsedItem = FindBankTeraOrb(bank);

u8 newType = GetTerastallizedNewType(terastallizedSpecies, moveType);

gBattleMons[bank].type1 = newType;
gBattleMons[bank].type2 = newType;

if (moveType == MOVE_TERABLAST) {
gBattleMons[bank].ppBonuses = newType;

return BattleScript_Terastallized;
}

static const u8* DoTerastal(u8 bank)
{
u16 terastalSpecies = GetTerastallizedSpecies(bank, TRUE);

if (terastalSpecies == SPECIES_NONE) //Can't Terastal
return NULL;

DoFormChange(bank, terastalSpecies, FALSE, FALSE, FALSE);

gBattleScripting.bank = bank;
gLastUsedItem = FindBankTeraOrb(bank);
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, terastalSpecies);

return BattleScript_Terastallized;
}

const u8* GetTerastallizedScript(u8 bank)
{
const u8* script = DoTerastal(bank);
if (script != NULL)
return script;

return DoTerastallized(bank);
}

void TerastalRevert(struct Pokemon* party)
{
u32 i;

for (i = 0; i < PARTY_SIZE; ++i)
TryRevertTerastal(&party);
}

void TryRevertTerastal(struct Pokemon* mon)
{
u16 baseSpecies = GetTerastalBaseForm(mon->species);

if (baseSpecies != SPECIES_NONE)
{
mon->species = baseSpecies;
mon->terastal = TRUE; //If encountered in the wild, now can permanently Terastal
CalculateMonStats(mon);
}
}

void TryRevertBankTerastal(u8 bank)
{
struct Pokemon* mon = GetBankPartyData(bank);
u16 baseSpecies = GetTerastalBaseForm(GetMonData(mon, MON_DATA_SPECIES, NULL));

if (baseSpecies != SPECIES_NONE) //Bank is terastallized - can't check timer because already reset
{
if (mon->backupSpecies != SPECIES_NONE)
baseSpecies = mon->backupSpecies;

DoFormChange(bank, baseSpecies, FALSE, FALSE, FALSE);
mon->terastal = TRUE; //If encountered in the wild, now can permanently Terastal
}
}

u16 GetTerastalSpecies(u16 species, bool8 canTerastal)
{
u32 i;
const struct Evolution* evolutions = gEvolutionTable[species];

if (canTerastal) //Mon can Terastal
{
for (i = 0; i < EVOS_PER_MON; ++i)
{
if (evolutions.method == EVO_NONE) //Most likely end of entries
break; //Break now to save time
else if (evolutions.method == EVO_TERASTAL)
{
//Ignore reversion information
if (evolutions.param == 0) continue;

//Any value other than 0 indicates Tera potential
return evolutions.targetSpecies;
}
}
}

return SPECIES_NONE;
}

u16 GetTerastalBaseForm(u16 species)
{
const struct Evolution* evolutions = gEvolutionTable[species];

for (u8 i = 0; i < EVOS_PER_MON; ++i)
{
if (evolutions.method == EVO_NONE) //Most likely end of entries
break; //Break now to save time
else if (evolutions.method == EVO_TERASTAL && evolutions.param == 0)
return evolutions.targetSpecies;
}

return SPECIES_NONE;
}

static bool8 IsItemTeraOrb(u16 item)
{
for (u8 i = 0; i < ARRAY_COUNT(sTeraOrbTable); ++i)
{
if (item == sTeraOrbTable)
return TRUE;
}

return FALSE;
}

static item_t FindTrainerTeraOrb(u16 trainerId)
{
if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK) || IsFrontierTrainerId(trainerId))
return ITEM_TERA_ORB;

for (u8 i = 0; i < TRAINER_ITEM_COUNT; ++i)
{
if (IsItemTeraOrb(gTrainers[trainerId].items))
return gTrainers[trainerId].items;
}

return ITEM_NONE;
}

static item_t FindPlayerTeraOrb(void)
{
if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK))
return ITEM_TERA_ORB;

#if (defined UNBOUND && defined VAR_KEYSTONE) //Mega Ring doubles as Tera Orb in Unbound
u16 teraorb = VarGet(VAR_KEYSTONE);
if (teraorb != ITEM_NONE)
return teraorb;
#else
for (u8 i = 0; i < ARRAY_COUNT(sTeraOrbTable); ++i)
{
if (CheckBagHasItem(sTeraOrbTable, 1))
return sTeraOrbTable;
}
#endif

#ifdef DEBUG_TERASTALLIZED
return ITEM_TERA_ORB; //Give player Tera Orb if they have none
#endif

return ITEM_NONE;
}

static item_t FindBankTeraOrb(u8 bank)
{
#ifdef DEBUG_TERASTALLIZED
if (bank + 1)
return ITEM_TERA_ORB;
#endif

if (SIDE(bank) == SIDE_OPPONENT)
{
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
if (GetBattlerPosition(bank) == B_POSITION_OPPONENT_LEFT)
return FindTrainerTeraOrb(gTrainerBattleOpponent_A);
else
return FindTrainerTeraOrb(SECOND_OPPONENT);
}
else
return FindTrainerTeraOrb(gTrainerBattleOpponent_A);
}
else //SIDE_PLAYER
{
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
if (GetBattlerPosition(bank) == B_POSITION_PLAYER_RIGHT)
return FindTrainerTeraOrb(VarGet(VAR_PARTNER));
else
return FindPlayerTeraOrb();
}
else
return FindPlayerTeraOrb();
}
}

bool8 TerastallizedEnabled(u8 bank)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED)
{
if (FindBankTeraOrb(bank) == ITEM_NONE)
{
#ifdef DEBUG_TERASTALLIZED
return TRUE;
#else
return FALSE;
#endif
}

return TRUE;
}

return FALSE;
}

bool8 HasBankTerastallizedAlready(u8 bank)
{
if ((SIDE(bank) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|| (SIDE(bank) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))
{
return gNewBS->terastallizedData.used[bank];
}

return gNewBS->terastallizedData.used[bank]
|| (IS_DOUBLE_BATTLE && gNewBS->terastallizedData.used[PARTNER(bank)]);
}

bool8 IsTerastalSpecies(u16 species)
{
const struct Evolution* evolutions = gEvolutionTable[species];

for (u8 i = 0; i < EVOS_PER_MON; ++i)
{
if (evolutions.method == EVO_NONE) //Most likely end of entries
break; //Break now to save time
else if (evolutions.method == EVO_TERASTAL && evolutions.param == FALSE)
return TRUE;
}

return FALSE;
}

bool8 IsTerastallized(u8 bank)
{
return gNewBS->terastallizedData.timer[bank] != 0;
}

bool8 IsTerastal(u8 bank)
{
return IsTerastalSpecies(GetBankPartyData(bank)->species);
}

bool8 HasTerastallizedSymbol(u8 bank)
{
return IsTerastallized(bank) || IsTerastallized(bank);
}

bool8 DoesTeratallizedUsageStopMegaEvolution(u8 bank)
{
return gNewBS->terastallizedData.used[bank]
&& gNewBS->terastallizedData.partyIndex[SIDE(bank)] & gBitTable[gBattlerPartyIndexes[bank]];
}

bool8 MonCanTerastallized(struct Pokemon* mon)
{
if (gBattleTypeFlags & BATTLE_TYPE_TERASTALLIZED)
{
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
u16 item = GetMonData(mon, MON_DATA_HELD_ITEM, NULL);

if (IsBannedTerastallizedSpecies(species)
|| IsBannedHeldItemForTerastallized(item))
return FALSE;

return TRUE;
}

return FALSE;
}

bool8 PlayerHasNoMonsLeftThatCanTerastallized(void)
{
u8 i, firstMonId, lastMonId;
struct Pokemon* party = LoadPartyRange(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), &firstMonId, &lastMonId);

for (i = firstMonId; i < lastMonId; ++i)
{
if (MON_CAN_BATTLE(&party)
&& MonCanTerastallized(&party))
return FALSE;
}

return TRUE;
}

void TryFadeBankPaletteForTerastallized(u8 bank, u16 paletteOffset)
{
if (IsTerastallized(bank)
{
u8 newType = GetTerastallizedNewType(SPECIES(bank), MOVE_TERABLAST);

switch (newType)
{
case TYPE_NORMAL:
BlendPalette(paletteOffset, 16, 4, RGB(190, 190, 190)); // Normal - Gris claro
break;
case TYPE_FIRE:
BlendPalette(paletteOffset, 16, 4, RGB(255, 69, 0)); // Fire - Rojo
break;
case TYPE_WATER:
BlendPalette(paletteOffset, 16, 4, RGB(0, 0, 255)); // Water - Azul
break;
case TYPE_GRASS:
BlendPalette(paletteOffset, 16, 4, RGB(0, 128, 0)); // Grass - Verde oscuro
break;
case TYPE_ELECTRIC:
BlendPalette(paletteOffset, 16, 4, RGB(255, 255, 0)); // Electric - Amarillo
break;
case TYPE_ICE:
BlendPalette(paletteOffset, 16, 4, RGB(173, 216, 230)); // Ice - Azul claro
break;
case TYPE_FIGHTING:
BlendPalette(paletteOffset, 16, 4, RGB(128, 0, 0)); // Fighting - Marrón oscuro
break;
case TYPE_POISON:
BlendPalette(paletteOffset, 16, 4, RGB(128, 0, 128)); // Poison - Morado oscuro
break;
case TYPE_GROUND:
BlendPalette(paletteOffset, 16, 4, RGB(139, 69, 19)); // Ground - Marrón
break;
case TYPE_FLYING:
BlendPalette(paletteOffset, 16, 4, RGB(135, 206, 250)); // Flying - Azul claro
break;
case TYPE_PSYCHIC:
BlendPalette(paletteOffset, 16, 4, RGB(255, 0, 255)); // Psychic - Magenta
break;
case TYPE_BUG:
BlendPalette(paletteOffset, 16, 4, RGB(34, 139, 34)); // Bug - Verde
break;
case TYPE_ROCK:
BlendPalette(paletteOffset, 16, 4, RGB(139, 69, 19)); // Rock - Marrón
break;
case TYPE_GHOST:
BlendPalette(paletteOffset, 16, 4, RGB(123, 104, 238)); // Ghost - Azul violeta
break;
case TYPE_DRAGON:
BlendPalette(paletteOffset, 16, 4, RGB(106, 90, 205)); // Dragon - Azul pálido
break;
case TYPE_DARK:
BlendPalette(paletteOffset, 16, 4, RGB(0, 0, 0)); // Dark - Negro
break;
case TYPE_STEEL:
BlendPalette(paletteOffset, 16, 4, RGB(192, 192, 192)); // Steel - Plata
break;
case TYPE_FAIRY:
BlendPalette(paletteOffset, 16, 4, RGB(255, 182, 193)); // Fairy - Rosa claro
case TYPE_STELLAR:
BlendPalette(paletteOffset, 16, 4, RGB(255, 255, 255)); // Stellar - Blanco claro
break

#ifdef NATIONAL_DEX_CALYREX
if (SpeciesToNationalPokedexNum(SPECIES(bank)) == NATIONAL_DEX_CALYREX)
BlendPalette(paletteOffset, 16, 4, RGB(0, 5, 31)); //Terastallized Blue
else
#endif
BlendPalette(paletteOffset, 16, 4, RGB(31, 0, 12)); //Terastallized Pinkish-Red

CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, 32);
}
}

void EndBattleTerastallizedRevert(u8 bank)
{
if (BATTLER_ALIVE(bank) && IsTerastallized(bank))
{
u16 hp, maxHP;
struct Pokemon* mon = GetBankPartyData(bank);

hp = GetBaseCurrentHP(bank);
maxHP = GetBaseMaxHP(bank);
SetMonData(mon, MON_DATA_HP, &hp);
SetMonData(mon, MON_DATA_MAX_HP, &maxHP);
gNewBS->terastallizedData.timer[bank] = 0;
}
}

//Called from Battle Script
void ClearBallAnimActiveBit(void)
{
gBattleSpritesDataPtr->healthBoxesData[gBattleScripting.bank].ballAnimActive = FALSE;
}



#include "../include/teratype.h"

struct EspeciesYTipos {
u16 especie;
u8 tipos[2]; // Cambia a 3 si permites más de un tipo
};

u8 GetTerastallizedNewType(void) {
static const u8 tiposDisponibles[] = {TYPE_NORMAL, TYPE_FIGHTING, TYPE_FLYING, TYPE_POISON, TYPE_GROUND, TYPE_ROCK, TYPE_BUG, TYPE_GHOST, TYPE_STEEL, TYPE_FIRE, TYPE_WATER, TYPE_GRASS, TYPE_ELECTRIC, TYPE_PSYCHIC, TYPE_ICE, TYPE_DRAGON, TYPE_DARK, TYPE_FAIRY, TYPE_STELLAR};
}

static const struct SpeciesYTypes speciesYTypes[] = {
{SPECIES_CHARIZARD, {TYPE_FIRE, TYPE_DRAGON}},
{SPECIES_BLASTOISE, {TYPE_WATER}},
// Agrega más especies y sus tipos según sea necesario
};

u8 GetTerastallizedNewType(u16 specie, u8 moveType) {
// Buscar la especie en la lista y verificar si el tipo del ataque coincide con alguno de los tipos de la especie
for (u8 i = 0; i < ARRAY_COUNT(speciesYTypes); ++i) {
if (speciesYTypes.specie == specie) {
if (speciesYTypes.types[0] == moveType || speciesYTypes.types[1] == moveType) {
// Si el tipo del ataque coincide con uno de los tipos de la especie, devolver ese tipo
return moveType;
} else {
// Si no coincide, devolver el primer tipo de la especie
return speciesYTypes.types[0];
}
}
}

// Si no se encuentra la especie, devolver un tipo predeterminado (Tipo Normal, por ejemplo)
return TYPE_NORMAL;
}



psdt:
solo dejo el codigo de la tera mas la base de datos donde iba a almacenar todos los pokemons con sus respectivos teratipos..

psdt2:
también dejo el trigger que iba a usar, el cual hice en 5 minutos xD
Tera_Trigger.png
 

Adjuntos

SakuraHaruno

Sakura Haruno Muerta
Interesante sinceramente hasta vi cuando la publicaste en discord preguntando pero puedo decir que si queda mejor en la (Animacion) sería como la mega evolución.


Ya que bueno es casi igual a la mega evolución.
 

AxelLoquendo

Todo terreno 👻
ACT-22-04-2024
Poco a poco va quedando la teracristalización, pero antes de ir de lleno a la mecánica decidí poner los teratipos y mostrarlo como 3er tipo en la sunmary screen, puse que los teratipos sean aleatorios en pokemons salvajes y regalados como los iniciales.

ahora si, iré con todo con la mecánica.

Teratype test.png


psdt: @Draizehn si c puede mi pana :>
 

Erkey830

Fuck off!
ACT-22-04-2024
Poco a poco va quedando la teracristalización, pero antes de ir de lleno a la mecánica decidí poner los teratipos y mostrarlo como 3er tipo en la sunmary screen, puse que los teratipos sean aleatorios en pokemons salvajes y regalados como los iniciales.

ahora si, iré con todo con la mecánica.

Ver el archivo adjunto 17038

psdt: @Draizehn si c puede mi pana :>
porque lo haces aleatorio el teratipo?
 

AxelLoquendo

Todo terreno 👻
porque lo haces aleatorio el teratipo?
más o menos por esto:
wikidex:
Los Pokémon salvajes aparecerán con un teratipo aleatorio. En las teraincursiones de evento los Pokémon pueden tener un teratipo fijo. Además, en Paldea existen encuentros especiales con ciertos Pokémon salvajes que tienen también un teratipo fijo.
 

Shiny_Miner

'El Creador del Mundo'
more or less like this:
wikidex:
Wild Pokémon will appear with a random Theratype. Pokémon in event Tera Raids may have a fixed Theratype. Additionally, in Paldea, there are special encounters with certain wild Pokémon that also have a fixed Theratype.
¿Puedes presentar la expansión CFRU y la generación 9 de DPE aquí? Mi español es malo xD
 

Shiny_Miner

'El Creador del Mundo'
Mi La idea es crear una copia del código de la megaevolución y realizar otros cambios en él. ¿Pueden ayudarme a hacerlo? Lo modificaré para que muestre el mensaje de terracristalización en lugar del mensaje de la megaevolución y El tipo tera también aparece en la pantalla de resumen, solo hace falta hacer que el tipo de movimientos sea efectivo cuando Pokémon terra evoluciona. @AxelLoquendo
 
Última edición:
Arriba