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.
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
ACT-20-04-2024
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.
¿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 "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;
}
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
ACT-20-04-2024
Aun no me rindo, ya voy por el intento 342 >:c
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.
Adjuntos
-
4,3 KB Visitas: 69
Última edición: