Registrarse

[pokeemerald] Añadir Paletas Adicionales a los Pokémon

KevinXDE

Usuario mítico
Bien, pues como dice el título, vamos a añadir paletas extra a un Pokémon. De normal, un Pokémon tiene una paleta normal y una versión variocolor, pero con este método vamos a añadir una paleta por Pokémon extra, de manera que podamos encontrar Pokémon normales, shinies y del color que queráis. ¿Qué utilidad tiene esto? Pues haced volar la imaginación. Por ejemplo, replicar los Pokémon rosa de Isla Rosada del anime, o en mi caso, voy a introducir paletas para Pokémon oscuros, pero esto os puede servir para cualquier otra idea que tengáis en mente.

Si queríamos tener Pokémon de otros colores, lo que hacíamos normalmente hace tiempo era sustituir la paleta variocolor, pero si queríamos conservarla entonces lo teníamos más difícil. Otra opción algo más complicada era introducir nuevos sprites, como si de nuevos Pokémon se tratasen. Esto por una parte estaba bien, ya que podías tener versiones de Pokémon ya existentes como Lugia Oscuro, con otros tipos, habilidades o lo que se te ocurriera. Sin embargo, dependiendo del número de Pokémon que queráis cambiar, crear formas alternativas no me parece una buena solución. Además si no sabías spritear y querías algo de calidad, o encontrabas algo por internet o estabas jodido.

¿Por qué he decidido hacer esto?

En Pokémon Colosseum, Pokémon Tempestad Oscura y Pokémon GO se hace uso de los Pokémon oscuros, y de por sí son sprites con el mismo color que el Pokémon normal, pero acompañados de un aura o con los ojos rojos. Pero como yo no sé spritear ni hacer más frames de manera que me queden decentes, he decidido seguir el caso de los Pokémon rosa del anime, Lugia oscuro o Mewtwo oscuro de Pokkén Tournament, los cuales SÍ cambian de color respecto al Pokémon original, y hacerlo así para cada Pokémon existente. Que además, spritear los 800 y pico Pokémon de 0 es una locura, existiendo ya sprites de buena calidad como los de la Pokeemerald Expansion, pudiendo simplemente coger estos y recolorearlos a gusto. Eso no quita que he tenido que recolorear y sacar las nuevas paletas, pero oye, aunque es un trabajazo, es bastante más sencillo.

Por cierto, recomiendo leer todo el tema antes de probar nada, ya que alguna información se me escapa y hay algún bug gráfico poco importante. Eso no quita que el sistema funcione bien, pero probablemente siga investigando el tema para hacerlo más dinámico. Dicho esto, vamos a empezar con el tutorial.

Lo primero que vamos a hacer será abrir el archivo pokeemerald/src/data.c

En las líneas 294 y 308 aproximadamente, encontraremos las definiciones de Pokémon shinies y su tabla de paletas.
Código:
#define SPECIES_SPRITE(species, sprite) [SPECIES_##species] = {sprite, 0x800, SPECIES_##species}
#define SPECIES_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species}
#define SPECIES_SHINY_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species + SPECIES_SHINY_TAG}

#include "data/pokemon_graphics/back_pic_table.h"
#include "data/pokemon_graphics/palette_table.h"
#include "data/pokemon_graphics/shiny_palette_table.h"
Debo decir que no sé en qué influye el SPECIES_SHINY_TAG, si buscamos en los archivos, vemos que su valor está definido a 5000. De todos modos, dejarlo no parece hacer malfuncionar el sistema, así que lo que vamos a hacer aquí es copiar y pegar justo debajo toda la linea de SPECIES_SHINY_PAL y toda la linea de shiny_palette_table.h, y ponerles otro nombre, en mi caso SPECIES_SHADOW_PAL y shadow_palette_table.h:
Código:
#define SPECIES_SPRITE(species, sprite) [SPECIES_##species] = {sprite, 0x800, SPECIES_##species}
#define SPECIES_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species}
#define SPECIES_SHINY_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species + SPECIES_SHINY_TAG}
#define SPECIES_SHADOW_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species + SPECIES_SHINY_TAG}

#include "data/pokemon_graphics/back_pic_table.h"
#include "data/pokemon_graphics/palette_table.h"
#include "data/pokemon_graphics/shiny_palette_table.h"
#include "data/pokemon_graphics/shadow_palette_table.h"
Ya hemos terminado con este archivo. Ahora, como hemos incluido la nueva tabla de paletas (shadow_palette_table.h en mi caso), hay que crear ese nuevo archivo en esa dirección. Podéis simplemente como antes, copiar y pegar el archivo palette_table.h que se encuentra en la carpeta pokeemerald/src/data/pokemon_graphics y cambiarle el nombre.


Abrimos el nuevo archivo, y lo que vamos a hacer es remplazar todas las instancias de "SPECIES_PAL" por el nombre que le hayáis definido en data.c, que en mi caso es "SPECIES_SHADOW_PAL", y remplazar todas las instancias de la palabra "gMonPalette" por la palabra que queráis, en mi caso, "gMonShadowPalette". Hay que procurar no remplazar todas de golpe y ser cuidadoso con las mayúsculas y minúsculas, ya que si no al compilar no os encontrará los archivos. Si no usáis la Pokeemerald Expansion podéis ignorar la parte de PaletteTableFemale.

Pasamos de esto:
Código:
const struct CompressedSpritePalette gMonShinyPaletteTable[] =
{
    SPECIES_SHINY_PAL(NONE, gMonShinyPalette_CircledQuestionMark),
    SPECIES_SHINY_PAL(BULBASAUR, gMonShinyPalette_Bulbasaur),
...

const struct CompressedSpritePalette gMonShinyPaletteTableFemale[] =
{
    SPECIES_SHINY_PAL(EEVEE, gMonShinyPalette_Eevee),
};
a esto:
Código:
const struct CompressedSpritePalette gMonShadowPaletteTable[] =
{
    SPECIES_SHADOW_PAL(NONE, gMonShadowPalette_CircledQuestionMark),
    SPECIES_SHADOW_PAL(BULBASAUR, gMonShadowPalette_Bulbasaur),
...

const struct CompressedSpritePalette gMonShadowPaletteTableFemale[] =
{
    SPECIES_SHADOW_PAL(EEVEE, gMonShadowPalette_Eevee),
};
Obviamente esto es más eficiente cuantos más Pokémon vayáis a cambiar (en mi caso todos). En el caso de que solo queráis introducir la paleta para algun Pokémon, solo tenéis que cambiar la palabra "gMonPalette" de los CompressedSpritePalette y de los Pokémon correspondientes, de manera que si el Pokémon no tiene la paleta quede así:
Código:
const struct CompressedSpritePalette gMonShadowPaletteTable[] =
{
    SPECIES_SHADOW_PAL(NONE, gMonPalette_CircledQuestionMark),
    SPECIES_SHADOW_PAL(BULBASAUR, gMonPalette_Bulbasaur),
...

const struct CompressedSpritePalette gMonShadowPaletteTableFemale[] =
{
    SPECIES_SHADOW_PAL(EEVEE, gMonPalette_Eevee),
};
Pasamos al siguiente archivo que es pokeemerald/include/data.h

Aquí buscamos la línea 98 aproximadamente, debemos encontrar esto:
Código:
extern const struct CompressedSpritePalette gMonShinyPaletteTable[];
Si usáis la Pokeemerald Expansion también encontraréis la misma tabla para las versiones hembra
Código:
extern const struct CompressedSpritePalette gMonShinyPaletteTableFemale[];
Debajo de estas ponemos nuestras nuevas tablas tal que así:
Código:
extern const struct CompressedSpritePalette gMonShinyPaletteTable[];
extern const struct CompressedSpritePalette gMonShinyPaletteTableFemale[];
extern const struct CompressedSpritePalette gMonShadowPaletteTable[];
extern const struct CompressedSpritePalette gMonShadowPaletteTableFemale[];
Guardamos y ahora abrimos el archivo pokeemerald/include/graphics.h

Aquí va a ser diferente dependiendo de si usamos la Pokeemerald Expansion o no, ya que el archivo está organizado de forma distinta. Si usáis la Pokeemerald Expansion la cosa es sencilla, aproximadamente en la línea 4668 (despúes de Shiny Shadow Rider Calyrex), debajo ponemos las nuevas paletas por cada Pokémon siguiendo la misma estructura:
Código:
extern const u32 gMonShadowPalette_CircledQuestionMark[];
extern const u32 gMonShadowPalette_DoubleQuestionMark[];
extern const u32 gMonShadowPalette_Bulbasaur[];
...
Si no usáis la Pokeemerald Expansion, en la linea 35 encontramos esto por cada Pokémon:
Código:
// pokemon gfx
extern const u32 gMonFrontPic_Bulbasaur[];
extern const u32 gMonPalette_Bulbasaur[];
extern const u32 gMonBackPic_Bulbasaur[];
extern const u32 gMonShinyPalette_Bulbasaur[];
extern const u32 gMonStillFrontPic_Bulbasaur[];
extern const u8 gMonIcon_Bulbasaur[];
extern const u8 gMonFootprint_Bulbasaur[];
Como antes, ponéis la nueva paleta debajo. Aquí es algo más tedioso porque sí que habría que hacerlo uno por uno, a menos que optéis por que os la sude la organización y lo pongáis al fondo del archivo xD.

Guardamos y nos vamos al archivo pokeemerald/src/data/graphics/pokemon.h

Al igual que antes, si usáis la Pokeemerald Expansion es diferente. El procedimiento es el mismo, solo que aquí buscaremos la última instancia de la palabra "Shiny" (al igual que antes, justo después de la forma de Calyrex).
Código:
const u32 gMonShadowPalette_CircledQuestionMark[] = INCBIN_U32("graphics/pokemon/question_mark/circled/shadow.gbapal.lz");
const u32 gMonShadowPalette_DoubleQuestionMark[] = INCBIN_U32("graphics/pokemon/question_mark/double/shadow.gbapal.lz");
const u32 gMonShadowPalette_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/shadow.gbapal.lz");
...
Si no usáis la Pokeemerald Expansion, el archivo estará organizado así por cada Pokémon:
Código:
const u32 gMonStillFrontPic_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/front.4bpp.lz");
const u32 gMonPalette_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/normal.gbapal.lz");
const u32 gMonBackPic_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/back.4bpp.lz");
const u32 gMonShinyPalette_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/shiny.gbapal.lz");
const u8 gMonIcon_Bulbasaur[] = INCBIN_U8("graphics/pokemon/bulbasaur/icon.4bpp");
const u8 gMonFootprint_Bulbasaur[] = INCBIN_U8("graphics/pokemon/bulbasaur/footprint.1bpp");
Ahora ya tenemos todos lo que viene siendo la nueva tabla de paletas en su sitio, solo queda añadir un archivo .pal en la carpeta de los Pokémon correspondientes como en esta foto. No os preocupéis por los archivos .gbapal o gbapal.lz, estos se crean automaticamente al compilar.


Si no sabéis como conseguir el archivo .pal, lo que yo he hecho ha sido coger los frontsprites y backsprites de las carpetas pokeemerald/graphics/pokemon/ y recolorearlos a parte, procurando sustituir todos los colores correctamente. Luego podéis sacar ese archivo .pal de los recolores, o como me gusta a mi, crearlo directamente de forma manual, que me quedo más tranquilo aunque lleve algo más de trabajo. Aquí el coñazo es que si usáis la Pokeemerald Expansion, los frontsprites son la version Normal, y los backsprites la version Shiny, mientras que si no usáis la Pokeemerald Expansion lo tenéis más fácil porque ambos sprites son la versión Normal. No recomiendo buscar sprites por internet y recolorearlos, lo he intentado y siempre hay diferencias, lo más seguro es usar los Sprites que ya vienen en las carpetas, a menos que vayáis a cambiarlos.

Una vez tenemos las paletas en su sitio, hay que hacer que estos Pokémon puedan salir como Pokémon salvajes. Nos vamos al archivo pokeemerald/include/constants/pokemon.h

Aquí buscamos la instancia "SHINY_ODDS", que es la constante que decide cuanto de raros son los Pokémon Shinies. Alrededor de la línea 91:
Código:
// Shiny odds
#define SHINY_ODDS 16 // Actual probability is SHINY_ODDS/65536
Añadiremos nuestra propia constante, en mi caso:
Código:
// Shiny odds
#define SHINY_ODDS 16 // Actual probability is SHINY_ODDS/65536
#define SHADOW_ODDS 656 // Actual probability is SHADOW_ODDS/65536
Haciendo cálculos más o menos sabréis cuanto será el porcentaje de aparición. 656 son aproximadamente 1 de cada 99. Os recomiendo un número más alto que el de SHINY_ODDS pero tampoco demasiado alto (rondando los 60,000), ya que puede dar problemas, pero podéis ir probando combinaciones. Si solo queréis comprobar que funciona y carga la nueva paleta, podéis probar un número como 60,312 (un 92% de aparición aproximadamente).

Ahora vamos a usar esa nueva constante, nos vamos al archivo pokeemerald/src/pokemon.c y buscamos la función void CreateBoxMon. Si no queremos que los entrenadores tengan estos Pokémon, hay que cambiar la constante SHINY_ODDS por la nuestra.
Código:
//Determine original trainer ID
if (otIdType == OT_ID_RANDOM_NO_SHINY) //Pokemon cannot be shiny
{
    u32 shinyValue;
    do
    {
        value = Random32();
        shinyValue = HIHALF(value) ^ LOHALF(value) ^ HIHALF(personality) ^ LOHALF(personality);
    } while (shinyValue < SHADOW_ODDS);
Ahora buscamos la función const u32 *GetMonSpritePalFromSpeciesAndPersonality. Yo la he cambiado así, para que os hagáis una idea:
Código:
const u32 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, u32 otId, u32 personality)
{
    u32 shinyValue;

    if (species > NUM_SPECIES)
        return gMonPaletteTable[0].data;

    shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality);
    if (shinyValue < SHINY_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return gMonShinyPaletteTableFemale[species].data;
        else
            return gMonShinyPaletteTable[species].data;
    }
    else if (shinyValue < SHADOW_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return gMonShadowPaletteTableFemale[species].data;
        else
            return gMonShadowPaletteTable[species].data;
    }
    else
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return gMonPaletteTableFemale[species].data;
        else
            return gMonPaletteTable[species].data;
    }
}
También buscaremos la función const struct CompressedSpritePalette *GetMonSpritePalStructFromOtIdPersonality que está justo debajo y la cambiaremos del mismo modo:
Código:
const struct CompressedSpritePalette *GetMonSpritePalStructFromOtIdPersonality(u16 species, u32 otId , u32 personality)
{
    u32 shinyValue;

    shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality);
    if (shinyValue < SHINY_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return &gMonShinyPaletteTableFemale[species];
        else
            return &gMonShinyPaletteTable[species];
    }
    else if (shinyValue < SHADOW_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return &gMonShadowPaletteTableFemale[species];
        else
            return &gMonShadowPaletteTable[species];
    }
    else
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return &gMonPaletteTableFemale[species];
        else
            return &gMonPaletteTable[species];
    }
}
Guardamos y ya está. Si compilamos ya tenemos las nuevas paletas disponibles!


Quedan dos pasos más, pero estos son opcionales. Resulta que hay una probabilidad de que cuando usemos un ShowPokePic, el Pokémon en cuestión se vuelva de esta paleta (si se la hemos puesto, claro). Eso quiere decir que, en mi caso, el Lotad de la introducción podría ser oscuro, o las imágenes de los iniciales de Hoenn, o las entradas de la Pokédex. Si no queréis que esto suceda, la solución está en los archivos siguientes:

pokeemerald/src/main_menu.c
pokeemerald/src/pokedex.c
pokeemerald/src/starter_choose.c

Simplemente buscamos "SHINY_ODDS" en esos archivos. Por lo que he entendido, lo que hace SHINY_ODDS ahí es, junto con el valor de su derecha, crear una personalidad al Pokémon de la imagen, de tal manera que a veces puede salir Shiny, o con nuestra nueva paleta. A mi la verdad es que nunca me ha pasado y para arreglarlo lo que he hecho ha sido sustituir SHINY_ODDS por 0, y al valor de la derecha le he puesto una personalidad fija (0x8000) de tal manera que el cálculo da que el Pokémon de la imagen siempre tenga los colores normales. Esto funciona siempre y cuando hayáis usado los mismos valores que yo en SHINY_ODDS y SHADOW_ODDS. Si no, tendréis que calcular una personalidad. En la función "void CreateBoxMon" mencionada anteriormente tenéis ejemplos de como se hace (la parte de HIHALF Y LOHALF). Si tenéis dudas con esto os puedo echar un cable. O probad números a voleo, eso siempre funciona (?)

Por ejemplo, el del archivo pokeemerald/src/pokedex.c pasa de esto:
Código:
u16 CreateMonSpriteFromNationalDexNumber(u16 nationalNum, s16 x, s16 y, u16 paletteSlot)
{
    nationalNum = NationalPokedexNumToSpecies(nationalNum);
    return CreateMonPicSprite(nationalNum, SHINY_ODDS, GetPokedexMonPersonality(nationalNum), TRUE, x, y, paletteSlot, 0xFFFF);
}
a esto:
Código:
u16 CreateMonSpriteFromNationalDexNumber(u16 nationalNum, s16 x, s16 y, u16 paletteSlot)
{
    nationalNum = NationalPokedexNumToSpecies(nationalNum);
    return CreateMonPicSprite(nationalNum, 0, 0x8000, TRUE, x, y, paletteSlot, 0xFFFF);
}
La función CreateMonPicSprite, si no usáis Pokeemerald Expansion, se llama CreateMonPicSprite_HandleDeoxys. Cuidado con eso.

Ya estaría todo, hay otra una última cosa opcional que se puede hacer, que es que cuando sale el Pokémon con dicha paleta, salten las estrellitas variocolor. Esto lo uso para diferenciar esta paleta de la normal. Sin embargo hay un pequeño bug gráfico que pasa a veces en combates dobles: el gráfico de las estrellitas se vuelve negro, pero no he sabido arreglarlo. Además, si no añadisteis paletas extra para todos los Pokémon, las estrellitas saldrán tambien con las versiones normales de los Pokémon (esto es debido a que su personalidad indica que debería tener la nueva paleta). No es grave, pero usadlo a sabiendas de esto: abrimos el archivo pokeemerald/src/battle_anim_throw.c y buscamos la función void TryShinyAnimation. Ahí cambiamos la constante SHINY_ODDS por la que hayamos creado nosotros, y ya estaría.


Es algo que probablemente poca gente va a usar, pero espero que a alguien le sirva. En adelante, cuando termine todo el sistema de Pokémon Oscuros que incluye efectividades y otros rollos, ya lo postearé en otro tema.
 

Eaas

Profesional de WaH
Bien, pues como dice el título, vamos a añadir paletas extra a un Pokémon. De normal, un Pokémon tiene una paleta normal y una versión variocolor, pero con este método vamos a añadir una paleta por Pokémon extra, de manera que podamos encontrar Pokémon normales, shinies y del color que queráis. ¿Qué utilidad tiene esto? Pues haced volar la imaginación. Por ejemplo, replicar los Pokémon rosa de Isla Rosada del anime, o en mi caso, voy a introducir paletas para Pokémon oscuros, pero esto os puede servir para cualquier otra idea que tengáis en mente.

Si queríamos tener Pokémon de otros colores, lo que hacíamos normalmente hace tiempo era sustituir la paleta variocolor, pero si queríamos conservarla entonces lo teníamos más difícil. Otra opción algo más complicada era introducir nuevos sprites, como si de nuevos Pokémon se tratasen. Esto por una parte estaba bien, ya que podías tener versiones de Pokémon ya existentes como Lugia Oscuro, con otros tipos, habilidades o lo que se te ocurriera. Sin embargo, dependiendo del número de Pokémon que queráis cambiar, crear formas alternativas no me parece una buena solución. Además si no sabías spritear y querías algo de calidad, o encontrabas algo por internet o estabas jodido.

¿Por qué he decidido hacer esto?

En Pokémon Colosseum, Pokémon Tempestad Oscura y Pokémon GO se hace uso de los Pokémon oscuros, y de por sí son sprites con el mismo color que el Pokémon normal, pero acompañados de un aura o con los ojos rojos. Pero como yo no sé spritear ni hacer más frames de manera que me queden decentes, he decidido seguir el caso de los Pokémon rosa del anime, Lugia oscuro o Mewtwo oscuro de Pokkén Tournament, los cuales SÍ cambian de color respecto al Pokémon original, y hacerlo así para cada Pokémon existente. Que además, spritear los 800 y pico Pokémon de 0 es una locura, existiendo ya sprites de buena calidad como los de la Pokeemerald Expansion, pudiendo simplemente coger estos y recolorearlos a gusto. Eso no quita que he tenido que recolorear y sacar las nuevas paletas, pero oye, aunque es un trabajazo, es bastante más sencillo.

Por cierto, recomiendo leer todo el tema antes de probar nada, ya que alguna información se me escapa y hay algún bug gráfico poco importante. Eso no quita que el sistema funcione bien, pero probablemente siga investigando el tema para hacerlo más dinámico. Dicho esto, vamos a empezar con el tutorial.

Lo primero que vamos a hacer será abrir el archivo pokeemerald/src/data.c

En las líneas 294 y 308 aproximadamente, encontraremos las definiciones de Pokémon shinies y su tabla de paletas.
Código:
#define SPECIES_SPRITE(species, sprite) [SPECIES_##species] = {sprite, 0x800, SPECIES_##species}
#define SPECIES_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species}
#define SPECIES_SHINY_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species + SPECIES_SHINY_TAG}

#include "data/pokemon_graphics/back_pic_table.h"
#include "data/pokemon_graphics/palette_table.h"
#include "data/pokemon_graphics/shiny_palette_table.h"
Debo decir que no sé en qué influye el SPECIES_SHINY_TAG, si buscamos en los archivos, vemos que su valor está definido a 5000. De todos modos, dejarlo no parece hacer malfuncionar el sistema, así que lo que vamos a hacer aquí es copiar y pegar justo debajo toda la linea de SPECIES_SHINY_PAL y toda la linea de shiny_palette_table.h, y ponerles otro nombre, en mi caso SPECIES_SHADOW_PAL y shadow_palette_table.h:
Código:
#define SPECIES_SPRITE(species, sprite) [SPECIES_##species] = {sprite, 0x800, SPECIES_##species}
#define SPECIES_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species}
#define SPECIES_SHINY_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species + SPECIES_SHINY_TAG}
#define SPECIES_SHADOW_PAL(species, pal) [SPECIES_##species] = {pal, SPECIES_##species + SPECIES_SHINY_TAG}

#include "data/pokemon_graphics/back_pic_table.h"
#include "data/pokemon_graphics/palette_table.h"
#include "data/pokemon_graphics/shiny_palette_table.h"
#include "data/pokemon_graphics/shadow_palette_table.h"
Ya hemos terminado con este archivo. Ahora, como hemos incluido la nueva tabla de paletas (shadow_palette_table.h en mi caso), hay que crear ese nuevo archivo en esa dirección. Podéis simplemente como antes, copiar y pegar el archivo palette_table.h que se encuentra en la carpeta pokeemerald/src/data/pokemon_graphics y cambiarle el nombre.


Abrimos el nuevo archivo, y lo que vamos a hacer es remplazar todas las instancias de "SPECIES_PAL" por el nombre que le hayáis definido en data.c, que en mi caso es "SPECIES_SHADOW_PAL", y remplazar todas las instancias de la palabra "gMonPalette" por la palabra que queráis, en mi caso, "gMonShadowPalette". Hay que procurar no remplazar todas de golpe y ser cuidadoso con las mayúsculas y minúsculas, ya que si no al compilar no os encontrará los archivos. Si no usáis la Pokeemerald Expansion podéis ignorar la parte de PaletteTableFemale.

Pasamos de esto:
Código:
const struct CompressedSpritePalette gMonShinyPaletteTable[] =
{
    SPECIES_SHINY_PAL(NONE, gMonShinyPalette_CircledQuestionMark),
    SPECIES_SHINY_PAL(BULBASAUR, gMonShinyPalette_Bulbasaur),
...

const struct CompressedSpritePalette gMonShinyPaletteTableFemale[] =
{
    SPECIES_SHINY_PAL(EEVEE, gMonShinyPalette_Eevee),
};
a esto:
Código:
const struct CompressedSpritePalette gMonShadowPaletteTable[] =
{
    SPECIES_SHADOW_PAL(NONE, gMonShadowPalette_CircledQuestionMark),
    SPECIES_SHADOW_PAL(BULBASAUR, gMonShadowPalette_Bulbasaur),
...

const struct CompressedSpritePalette gMonShadowPaletteTableFemale[] =
{
    SPECIES_SHADOW_PAL(EEVEE, gMonShadowPalette_Eevee),
};
Obviamente esto es más eficiente cuantos más Pokémon vayáis a cambiar (en mi caso todos). En el caso de que solo queráis introducir la paleta para algun Pokémon, solo tenéis que cambiar la palabra "gMonPalette" de los CompressedSpritePalette y de los Pokémon correspondientes, de manera que si el Pokémon no tiene la paleta quede así:
Código:
const struct CompressedSpritePalette gMonShadowPaletteTable[] =
{
    SPECIES_SHADOW_PAL(NONE, gMonPalette_CircledQuestionMark),
    SPECIES_SHADOW_PAL(BULBASAUR, gMonPalette_Bulbasaur),
...

const struct CompressedSpritePalette gMonShadowPaletteTableFemale[] =
{
    SPECIES_SHADOW_PAL(EEVEE, gMonPalette_Eevee),
};
Pasamos al siguiente archivo que es pokeemerald/include/data.h

Aquí buscamos la línea 98 aproximadamente, debemos encontrar esto:
Código:
extern const struct CompressedSpritePalette gMonShinyPaletteTable[];
Si usáis la Pokeemerald Expansion también encontraréis la misma tabla para las versiones hembra
Código:
extern const struct CompressedSpritePalette gMonShinyPaletteTableFemale[];
Debajo de estas ponemos nuestras nuevas tablas tal que así:
Código:
extern const struct CompressedSpritePalette gMonShinyPaletteTable[];
extern const struct CompressedSpritePalette gMonShinyPaletteTableFemale[];
extern const struct CompressedSpritePalette gMonShadowPaletteTable[];
extern const struct CompressedSpritePalette gMonShadowPaletteTableFemale[];
Guardamos y ahora abrimos el archivo pokeemerald/include/graphics.h

Aquí va a ser diferente dependiendo de si usamos la Pokeemerald Expansion o no, ya que el archivo está organizado de forma distinta. Si usáis la Pokeemerald Expansion la cosa es sencilla, aproximadamente en la línea 4668 (despúes de Shiny Shadow Rider Calyrex), debajo ponemos las nuevas paletas por cada Pokémon siguiendo la misma estructura:
Código:
extern const u32 gMonShadowPalette_CircledQuestionMark[];
extern const u32 gMonShadowPalette_DoubleQuestionMark[];
extern const u32 gMonShadowPalette_Bulbasaur[];
...
Si no usáis la Pokeemerald Expansion, en la linea 35 encontramos esto por cada Pokémon:
Código:
// pokemon gfx
extern const u32 gMonFrontPic_Bulbasaur[];
extern const u32 gMonPalette_Bulbasaur[];
extern const u32 gMonBackPic_Bulbasaur[];
extern const u32 gMonShinyPalette_Bulbasaur[];
extern const u32 gMonStillFrontPic_Bulbasaur[];
extern const u8 gMonIcon_Bulbasaur[];
extern const u8 gMonFootprint_Bulbasaur[];
Como antes, ponéis la nueva paleta debajo. Aquí es algo más tedioso porque sí que habría que hacerlo uno por uno, a menos que optéis por que os la sude la organización y lo pongáis al fondo del archivo xD.

Guardamos y nos vamos al archivo pokeemerald/src/data/graphics/pokemon.h

Al igual que antes, si usáis la Pokeemerald Expansion es diferente. El procedimiento es el mismo, solo que aquí buscaremos la última instancia de la palabra "Shiny" (al igual que antes, justo después de la forma de Calyrex).
Código:
const u32 gMonShadowPalette_CircledQuestionMark[] = INCBIN_U32("graphics/pokemon/question_mark/circled/shadow.gbapal.lz");
const u32 gMonShadowPalette_DoubleQuestionMark[] = INCBIN_U32("graphics/pokemon/question_mark/double/shadow.gbapal.lz");
const u32 gMonShadowPalette_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/shadow.gbapal.lz");
...
Si no usáis la Pokeemerald Expansion, el archivo estará organizado así por cada Pokémon:
Código:
const u32 gMonStillFrontPic_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/front.4bpp.lz");
const u32 gMonPalette_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/normal.gbapal.lz");
const u32 gMonBackPic_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/back.4bpp.lz");
const u32 gMonShinyPalette_Bulbasaur[] = INCBIN_U32("graphics/pokemon/bulbasaur/shiny.gbapal.lz");
const u8 gMonIcon_Bulbasaur[] = INCBIN_U8("graphics/pokemon/bulbasaur/icon.4bpp");
const u8 gMonFootprint_Bulbasaur[] = INCBIN_U8("graphics/pokemon/bulbasaur/footprint.1bpp");
Ahora ya tenemos todos lo que viene siendo la nueva tabla de paletas en su sitio, solo queda añadir un archivo .pal en la carpeta de los Pokémon correspondientes como en esta foto. No os preocupéis por los archivos .gbapal o gbapal.lz, estos se crean automaticamente al compilar.


Si no sabéis como conseguir el archivo .pal, lo que yo he hecho ha sido coger los frontsprites y backsprites de las carpetas pokeemerald/graphics/pokemon/ y recolorearlos a parte, procurando sustituir todos los colores correctamente. Luego podéis sacar ese archivo .pal de los recolores, o como me gusta a mi, crearlo directamente de forma manual, que me quedo más tranquilo aunque lleve algo más de trabajo. Aquí el coñazo es que si usáis la Pokeemerald Expansion, los frontsprites son la version Normal, y los backsprites la version Shiny, mientras que si no usáis la Pokeemerald Expansion lo tenéis más fácil porque ambos sprites son la versión Normal. No recomiendo buscar sprites por internet y recolorearlos, lo he intentado y siempre hay diferencias, lo más seguro es usar los Sprites que ya vienen en las carpetas, a menos que vayáis a cambiarlos.

Una vez tenemos las paletas en su sitio, hay que hacer que estos Pokémon puedan salir como Pokémon salvajes. Nos vamos al archivo pokeemerald/include/constants/pokemon.h

Aquí buscamos la instancia "SHINY_ODDS", que es la constante que decide cuanto de raros son los Pokémon Shinies. Alrededor de la línea 91:
Código:
// Shiny odds
#define SHINY_ODDS 16 // Actual probability is SHINY_ODDS/65536
Añadiremos nuestra propia constante, en mi caso:
Código:
// Shiny odds
#define SHINY_ODDS 16 // Actual probability is SHINY_ODDS/65536
#define SHADOW_ODDS 656 // Actual probability is SHADOW_ODDS/65536
Haciendo cálculos más o menos sabréis cuanto será el porcentaje de aparición. 656 son aproximadamente 1 de cada 99. Os recomiendo un número más alto que el de SHINY_ODDS pero tampoco demasiado alto (rondando los 60,000), ya que puede dar problemas, pero podéis ir probando combinaciones. Si solo queréis comprobar que funciona y carga la nueva paleta, podéis probar un número como 60,312 (un 92% de aparición aproximadamente).

Ahora vamos a usar esa nueva constante, nos vamos al archivo pokeemerald/src/pokemon.c y buscamos la función void CreateBoxMon. Si no queremos que los entrenadores tengan estos Pokémon, hay que cambiar la constante SHINY_ODDS por la nuestra.
Código:
//Determine original trainer ID
if (otIdType == OT_ID_RANDOM_NO_SHINY) //Pokemon cannot be shiny
{
    u32 shinyValue;
    do
    {
        value = Random32();
        shinyValue = HIHALF(value) ^ LOHALF(value) ^ HIHALF(personality) ^ LOHALF(personality);
    } while (shinyValue < SHADOW_ODDS);
Ahora buscamos la función const u32 *GetMonSpritePalFromSpeciesAndPersonality. Yo la he cambiado así, para que os hagáis una idea:
Código:
const u32 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, u32 otId, u32 personality)
{
    u32 shinyValue;

    if (species > NUM_SPECIES)
        return gMonPaletteTable[0].data;

    shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality);
    if (shinyValue < SHINY_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return gMonShinyPaletteTableFemale[species].data;
        else
            return gMonShinyPaletteTable[species].data;
    }
    else if (shinyValue < SHADOW_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return gMonShadowPaletteTableFemale[species].data;
        else
            return gMonShadowPaletteTable[species].data;
    }
    else
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return gMonPaletteTableFemale[species].data;
        else
            return gMonPaletteTable[species].data;
    }
}
También buscaremos la función const struct CompressedSpritePalette *GetMonSpritePalStructFromOtIdPersonality que está justo debajo y la cambiaremos del mismo modo:
Código:
const struct CompressedSpritePalette *GetMonSpritePalStructFromOtIdPersonality(u16 species, u32 otId , u32 personality)
{
    u32 shinyValue;

    shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality);
    if (shinyValue < SHINY_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return &gMonShinyPaletteTableFemale[species];
        else
            return &gMonShinyPaletteTable[species];
    }
    else if (shinyValue < SHADOW_ODDS)
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return &gMonShadowPaletteTableFemale[species];
        else
            return &gMonShadowPaletteTable[species];
    }
    else
    {
        if (SpeciesHasGenderDifference[species] && GetGenderFromSpeciesAndPersonality(species, personality) == MON_FEMALE)
            return &gMonPaletteTableFemale[species];
        else
            return &gMonPaletteTable[species];
    }
}
Guardamos y ya está. Si compilamos ya tenemos las nuevas paletas disponibles!


Quedan dos pasos más, pero estos son opcionales. Resulta que hay una probabilidad de que cuando usemos un ShowPokePic, el Pokémon en cuestión se vuelva de esta paleta (si se la hemos puesto, claro). Eso quiere decir que, en mi caso, el Lotad de la introducción podría ser oscuro, o las imágenes de los iniciales de Hoenn, o las entradas de la Pokédex. Si no queréis que esto suceda, la solución está en los archivos siguientes:

pokeemerald/src/main_menu.c
pokeemerald/src/pokedex.c
pokeemerald/src/starter_choose.c

Simplemente buscamos "SHINY_ODDS" en esos archivos. Por lo que he entendido, lo que hace SHINY_ODDS ahí es, junto con el valor de su derecha, crear una personalidad al Pokémon de la imagen, de tal manera que a veces puede salir Shiny, o con nuestra nueva paleta. A mi la verdad es que nunca me ha pasado y para arreglarlo lo que he hecho ha sido sustituir SHINY_ODDS por 0, y al valor de la derecha le he puesto una personalidad fija (0x8000) de tal manera que el cálculo da que el Pokémon de la imagen siempre tenga los colores normales. Esto funciona siempre y cuando hayáis usado los mismos valores que yo en SHINY_ODDS y SHADOW_ODDS. Si no, tendréis que calcular una personalidad. En la función "void CreateBoxMon" mencionada anteriormente tenéis ejemplos de como se hace (la parte de HIHALF Y LOHALF). Si tenéis dudas con esto os puedo echar un cable. O probad números a voleo, eso siempre funciona (?)

Por ejemplo, el del archivo pokeemerald/src/pokedex.c pasa de esto:
Código:
u16 CreateMonSpriteFromNationalDexNumber(u16 nationalNum, s16 x, s16 y, u16 paletteSlot)
{
    nationalNum = NationalPokedexNumToSpecies(nationalNum);
    return CreateMonPicSprite(nationalNum, SHINY_ODDS, GetPokedexMonPersonality(nationalNum), TRUE, x, y, paletteSlot, 0xFFFF);
}
a esto:
Código:
u16 CreateMonSpriteFromNationalDexNumber(u16 nationalNum, s16 x, s16 y, u16 paletteSlot)
{
    nationalNum = NationalPokedexNumToSpecies(nationalNum);
    return CreateMonPicSprite(nationalNum, 0, 0x8000, TRUE, x, y, paletteSlot, 0xFFFF);
}
La función CreateMonPicSprite, si no usáis Pokeemerald Expansion, se llama CreateMonPicSprite_HandleDeoxys. Cuidado con eso.

Ya estaría todo, hay otra una última cosa opcional que se puede hacer, que es que cuando sale el Pokémon con dicha paleta, salten las estrellitas variocolor. Esto lo uso para diferenciar esta paleta de la normal. Sin embargo hay un pequeño bug gráfico que pasa a veces en combates dobles: el gráfico de las estrellitas se vuelve negro, pero no he sabido arreglarlo. Además, si no añadisteis paletas extra para todos los Pokémon, las estrellitas saldrán tambien con las versiones normales de los Pokémon (esto es debido a que su personalidad indica que debería tener la nueva paleta). No es grave, pero usadlo a sabiendas de esto: abrimos el archivo pokeemerald/src/battle_anim_throw.c y buscamos la función void TryShinyAnimation. Ahí cambiamos la constante SHINY_ODDS por la que hayamos creado nosotros, y ya estaría.


Es algo que probablemente poca gente va a usar, pero espero que a alguien le sirva. En adelante, cuando termine todo el sistema de Pokémon Oscuros que incluye efectividades y otros rollos, ya lo postearé en otro tema.
Lo que veo x aqui es interesante y es de las pocas cosas que si utilizas bien le puedan dar ese toque de unico a un juego, me agrado y aunque creo que no lo use alguien lo va a hacer, estoy totalmente seguro. Muy bueno el tuto y gracias por aportar tu investigacion
 

Kaktus

Miembro insignia
Miembro insignia
¡¡Que maldito genio Kevin!!

Gran investigación sin duda, seguro que le sacaremos mucho provecho y nos ahorrará mucho trabajo. Eres prometedor, espero seguir viendo más tutos así por aquí ❤
 

deidara9216

Profesional de WaH
Tengo una duda, como recoloreo un sprite, osea ya existe uno pero quiero cambiarlo por un sprite que veo mejor, como puedo editar la tabla .pal y con que herramienta puedo sacar esto.

Ya que al abrirlalos valores estan en orden aleatorio o bien si la abres con alguna herramienta que muestre los valores de paleta no concuerda con la que esta en el repositorio de los graficos.
 

KevinXDE

Usuario mítico
Tengo una duda, como recoloreo un sprite, osea ya existe uno pero quiero cambiarlo por un sprite que veo mejor, como puedo editar la tabla .pal y con que herramienta puedo sacar esto.

Ya que al abrirlalos valores estan en orden aleatorio o bien si la abres con alguna herramienta que muestre los valores de paleta no concuerda con la que esta en el repositorio de los graficos.
No entiendo muy bien tu pregunta, pero voy a intentar responder de todos modos con la manera en que yo lo hago. Las herramientas principales que uso para los sprites son GraphicsGale y paint.net

Para recolorear un sprite, lo primero de todo debes tener el frontsprite y backsprite (que suele ser variocolor) con la misma paleta. En GraphicsGale esto es muy sencillo, lo pongo paso por paso:

1. Abrir ambos archivos
2. Seleccionar el frontsprite y copiarlo al portapapeles
3. Seleccionar el backsprite (variocolor) y darle a load palette
4. Hacer click en 'File' > 'Import From Clipboard'
5. Deseleccionar la pestaña 'Match Pixels with Colors' y hacer click en 'All' > 'Ok'

Incluso se puede hacer al revés y tener el frontsprite de color shiny si te va mejor.

Luego cojo ambos archivos e intento recolorear en paint.net, ya que para buscar colores y recolorear es más rápido, sustituyendo cada color con uno nuevo y viendo si va quedando bien. Si por el contrario algunas outlines se ven mal o algunos colores no combinan, es cosa de editar los sprites originales. Te sorprendería el número de sprites que parece que están bien hechos pero luego te dan quebraderos de cabeza por lo mal hechos que están. Si ocurre esto tengo tambien que editar los archivos normal.pal y shiny.pal del Pokémon para que cuadren, y contrastar que las dos versiones se siguen viendo bien, haciendo el mismo proceso que antes en GraphicsGale. Tambien recalcar que si se editan estos sprites, también hay que editar los sprites animados, si los tiene el Pokémon

En cuanto tengo el sprite bien y el recolor queda como quiero, cojo una copia de los sprites nuevos (con los colores originales) y vuelvo a recolorear pero en GraphicsGale, de manera que cada color queda en la paleta en el lugar correspondiente y así se puede extraer la nueva paleta de manera más sencilla. Es bastante tedioso el proceso, pero es la manera más sencilla y rápida que conozco.

En principio la tabla de paletas no se tiene que tocar en ningún momento si ya has seguido el tutorial. Es simplemente para no cargarte la version normal o shiny de un Pokémon y poder añadir otra paleta. Si lo que quieres es sustituir una de las dos paletas, solo necesitas la nueva paleta y llamarla normal.pal o shiny.pal

Como digo, si te explicas mejor quizás puedo ayudarte mejor. Por otra parte, ando retocando todos los sprites de pokeemerald_expansion para hacerlos editables de manera sencilla, así que si pretendes editar muchos sprites yo quizás me esperaría, ya que compartiré algún repositorio o algo
 
Última edición:
Arriba