View Single Post
Old 22nd October 2013, 12:40 PM  
Jambo51
Glory To Arstotzka
Ex-Staff
 
Jambo51's Avatar
 
Join Date: May 2012
Location: Scotland
Posts: 85
Jambo51
Default Jambo51's Homebrew Pokémon Engine

Hello, intrepid reader! If you're looking at this thread, you have likely realised that there are several frustrating limits in the Gen III Pokémon game engines, which can badly alter how you wish to go about creating a hack.

What this project aims to do is offer a free to use, open source engine to base your crazy and creative hacks on!

Features:
All 649 Pokémon from Kanto, Johto, Hoenn, Sinnoh and Unova are in the base.
Built in brand new music engine especially coded to run music from the GB games with minimal conversion.
Built in RTC and Day and Night Cycle.
Fairy type (as well as all the old regular types!)

Planned Features:
Standard Pokémon features (battles, etc)
Seasonal Cycles (Day is shorter is Winter, etc)
Either Maxmod or potentially M4AA engine for 16 bit music (M4AA is Sappy to most people).

May add:
Kalos Pokémon
Contests (in spite of the fact that I personally dislike them)

Suggestions are welcome, and constructive criticism is welcomed!
The engine is planned to use the same scripting languages as the actual Gen III games, so no downloading new tools or learning new languages for this!

Details on major changes (Skip unless you're planning to ASM hack the engine):
Spoiler:
The Pokémon structure has been changed somewhat, separating out many PID dependent features into their own memory locations. Further details can be found in documentation.

The Real Time Clock data is (currently) held at 0x03000180, format being:
Year - u16
Month - u8
Day - u8
Day of week - u8
Hour - u8
Minute - u8
Second - u8
Time of Day - u8
Season - u8 (when implemented)

Flags are currently held at 0x0200F83C and are accessed in a bit wise manner, just like the original games. The valid flags range is 0x1 - 0x1FFF.

Variables are currently held at (unknown) and have a range of 0x0000 to 0xFFFF for values. the valid ranges of variables are from 0x4000 to 0x41FF, and 0x8000 to 0x801F.

The seen and caught flags for the Pokédex are held at (unknown), and are accessed as flags. the valid range of these is (technically) 0x1 to 0x290, but obviously, those flags above 0x289 are unused.

The Pokémon structure is held at (unknown) and follows the same structure as defined in the documentation.


Some screenshots:

Typedefs for Project:
Spoiler:
//
// customtypes.h:
//


#ifndef CUSTOMTYPES_H
#define CUSTOMTYPES_H

// --- primary typedefs ---
typedef enum { Time_Day, Time_Morning, Time_Afternoon, Time_Night } Times;

typedef enum { Flag_Null, Flag_RunningShoes, Flag_RunningShoesOn, Flag_UsingGBP } Flags;

typedef struct MovesetEntry {
u16 moveID;
u8 level;
u8 unused;
} MovesetEntry;

typedef struct Block {
u32 bottom[2];
u32 top[2];
} Block;

typedef struct MapConnectionData {
u32 type;
s32 offset;
u8 mapBank;
u8 map;
u16 alignment;
} MapConnectionData;

typedef struct MapConnection {
u32 numberOfConnections;
MapConnectionData* mainData[];
} MapConnection;

typedef struct PrimaryTileset {
u32 information;
u16* tilesetData[0x5000];
u16* paletteData1[0x400];
Block* blockData[0x280];
u32* blockAnimations[0x280];
u32* blockInformation[0x280];
} PrimaryTileset;

typedef struct SecondaryTileset {
u32 information;
u16* tilesetData[0x3000];
u16* paletteData2[0x400];
Block* blockData[0x100];
u32* blockAnimations[0x100];
u32* blockInformation[0x100];
} SecondaryTileset;

typedef struct MapFooter {
u32 width;
u32 height;
u16* borderBlocks;
u16* mapDataLocation;
PrimaryTileset* primaryTileset;
SecondaryTileset* secondaryTileset;
u8 borderWidth;
u8 borderHeight;
u16 alignment;
} MapFooter;

typedef struct LevelScript
{
u8 type;
u8* scriptLocation; // unaligned, make sure to load using loop
} LevelScript;

typedef struct WildPokemonEntry
{
u16 species;
u8 minLevel;
u8 maxLevel;
} WildPokemonEntry;

typedef struct WildGrassPokemonData
{
u32 information;
WildPokemonEntry* wildData[12];
} WildGrassPokemonData;

typedef struct WildWaterPokemonData
{
u32 information;
WildPokemonEntry* wildData[10];
} WildWaterPokemonData;

typedef struct WildTreePokemonData
{
u32 information;
WildPokemonEntry* wildData[5];
} WildTreePokemonData;

typedef struct WildFishingRodPokemonData
{
u32 information;
WildPokemonEntry* wildData[12];
} WildFishingRodPokemonData;

typedef struct WildData
{
WildGrassPokemonData* grassData;
WildWaterPokemonData* waterData;
WildTreePokemonData* treeData;
WildTreePokemonData* rockSmashData;
WildFishingRodPokemonData* fishingRodData;
} WildData;

typedef struct MapHeader {
MapFooter* footerLocation;
u32* eventsLocation;
LevelScript* levelScriptsLocation;
MapConnection* connections;
u16 musicTrack;
u8 mapBank;
u8 map;
u8 mapNameID;
u8 caveStatus;
u8 weatherType;
u8 lightStatus;
u8 unknown;
u8 escapeRopeType;
u8 showName;
u8 battleType;
WildData* wildDataLocation;
} MapHeader;

typedef struct AbridgedPokemon {
u32 personalityID;
u32 originalTrainerID;
char nickname[11];
u8 ability;
char originalTrainerName[7];
u8 mark;
u16 checksum;
u8 gender;
u8 nature;
u16 species;
u16 heldItem;
u32 experience:21;
u32 formeValue:10;
u32 forceShiny:1;
u8 ppBonuses;
u8 friendship;
u8 type1;
u8 type2;
u16 move1;
u16 move2;
u16 move3;
u16 move4;
u8 move1PP;
u8 move2PP;
u8 move3PP;
u8 move4PP;
u8 hpEV;
u8 attackEV;
u8 defenceEV;
u8 speedEV;
u8 specialAttackEV;
u8 specialDefenceEV;
u8 coolness;
u8 beauty;
u8 cuteness;
u8 smartness;
u8 toughness;
u8 feel;
u8 pokerusStatus:1;
u8 pokeBall:7;
u8 metLocation;
u8 catchLevel;
u8 originsInfo;
u32 hpIV:5;
u32 attackIV:5;
u32 defenceIV:5;
u32 speedIV:5;
u32 specialAttackIV:5;
u32 specialDefenceIV:5;
u32 isEgg:1;
u32 isObedient:1;
u32 ribbons;
} AbridgedPokemon;

typedef struct Pokemon {
AbridgedPokemon mainData;
u32 statusAilment;
u8 level;
u8 pokerusRemaining;
u16 currentHP;
u16 maximumHP;
u16 attack;
u16 defence;
u16 speed;
u16 specialAttack;
u16 specialDefence;
} Pokemon;

typedef struct BagItem {
u16 quantity;
u16 itemID;
} BagItem;

typedef struct Player {
u32 trainerID;
char name[8];
u8 gender;
u8 alignment1;
u16 hoursPlayed;
u8 minutesPlayed;
u8 secondsPlayed;
u8 framesPlayed;
u8 alignment2;
u16 options;
} Player;

typedef struct Buffer {
char text[20];
} Buffer;

typedef struct DexEntry {
u16 seenCaughtValue;
u16 speciesValue;
char* textPointer;
} DexEntry;

typedef struct BaseData {
u8 baseHP;
u8 baseAttack;
u8 baseDefence;
u8 baseSpeed;
u8 baseSpecialAttack;
u8 baseSpecialDefence;
u8 type1;
u8 type2;
u8 catchRate;
u8 genderSplitByte;
u16 EVYield;
u16 item1;
u16 item2;
u16 baseExpYield;
u8 hatchSteps;
u8 baseFriendship;
u8 levelUpType;
u8 eggGroup1;
u8 eggGroup2;
u8 ability1;
u8 ability2;
u8 hiddenAbility;
u8 safariZoneFleeRate;
u8 colour;
} BaseData;

typedef struct RealTimeClock {
u16 year;
u8 month;
u8 day;
u8 dayOfWeek;
u8 hour;
u8 minute;
u8 second;
u8 timeOfDay;
} RealTimeClock;

typedef enum Types {
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_NONE
} Types;

typedef struct Bag {
u32 bagInformation;
BagItem bagItemsData[40];
BagItem keyItemsData[30];
BagItem ballItemsData[20];
BagItem TMData[103];
BagItem berryItemsData[30];
} Bag;

typedef struct PokemonStorageBoxes {
u32 currentBoxID;
AbridgedPokemon boxData[25][30];
} PokemonStorageBoxes;

typedef struct NoiseRegister {
u32 soundLength:6;
u32 unused1:2;
u32 volumeEnvelopeSpeed:3;
u32 volumeEnvelopeDirection:1;
u32 initialVolume:4;
u32 unused2:16;
u32 dividingRatioOfFrequencies:3;
u32 counterStepWidth:1; // 0 = 15 bits, 1 = 7 bits
u32 shiftClockFrequency:4;
u32 unused3:6;
u32 lengthUseFlag:1;
u32 initialise:1;
u32 unused4:16;
} NoiseRegister;

typedef struct WavePattern {
u32 part1;
u32 part2;
u32 part3;
u32 part4;
} WavePattern;

typedef struct ToneData {
u8* nextInstruction;
u8* returnLocation;
u8 frameDelay;
s8 pitchBend;
s8 keyShift;
u8 currentOctave;
u16 pitch;
u8 currentVoice;
u8 fadeSpeed;
u16 modulation;
u8 channelVolume;
u8 fadeDirection;
u8 velocity;
u8 loopCounter;
s8 pan;
u8 noteLength;
u16 tone;
u16 unused;
} ToneData;

typedef struct WaveData {
u8* nextInstruction;
u8* returnLocation;
u8 frameDelay;
u8 loopCounter;
s8 keyShift;
u8 currentOctave;
u16 pitch;
u8 velocity;
u8 currentVoice;
u16 modulation;
u8 pan;
u8 noteLength;
} WaveData;

typedef struct NoiseData {
u8* nextInstruction;
u8* returnLocation;
} NoiseData;

typedef struct GBPMusicStruct {
u16 tempo;
u16 tone1Included:1;
u16 tone2Included:1;
u16 waveIncluded:1;
u16 noiseIncluded:1;
u16 unused:12;
ToneData tone1;
ToneData tone2;
WaveData wave;
NoiseData noise;
} GBPMusicStruct;

typedef struct GBPTrack {
u32 trackType:2;
u32 secondaryTracks:1;
u32 unused:29;
u8* songData;
} GBPTrack;

typedef struct GBPTrackHeader {
u32 tone1Included:1;
u32 tone2Included:1;
u32 waveIncluded:1;
u32 noiseIncluded:1;
u32 numberOfTracks:3;
u32 unused:25;
GBPTrack theTracks[];
} GBPTrackHeader;

typedef struct MoveData {
u16 effectID;
u8 basePower;
u8 type;
u8 accuracy;
u8 basePP;
u8 effectAccuracy;
u8 targets;
s8 priority;
u8 specialFlags;
u8 category;
u8 padding;
} MoveData;

/*Normal
Fighting
Flying
Poison
Ground
Rock
Bug
Ghost
Steel
Fire
Water
Grass
Electric
Psychic
Ice
Dragon
Dark
Fairy
???*/

#define TILESET_TILESET_DATA_OFFSET 4
#define TILESET_PALETTE_DATA_OFFSET 8
#define TILESET_BLOCKS_DATA_OFFSET 12

#define EWRAM_LOCATION __attribute__((section (".sbss")))

#endif // TOOLBOX_H
__________________
I have nothing interesting to add

Last edited by Jambo51; 27th October 2013 at 06:43 PM.
Jambo51 is offline   Reply With Quote