PHO - Pokémon Hackers Online

PHO - Pokémon Hackers Online (http://pokemonhackersonline.com/index.php)
-   Homebrew Projects (http://pokemonhackersonline.com/forumdisplay.php?f=163)
-   -   Jambo51's Homebrew Pokémon Engine (http://pokemonhackersonline.com/showthread.php?t=14443)

Jambo51 22nd October 2013 12:40 PM

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

Pia Carrot 22nd October 2013 12:53 PM

Sounds great, may even consider hacking again when this comes out.

Team Fail 22nd October 2013 02:09 PM

I actually really like this. I'm just curious, is it possible at all to toggle the Fairy-Type in case we don't want it?

Jambo51 22nd October 2013 03:21 PM

Quote:

Originally Posted by Team Fail (Post 126309)
I actually really like this. I'm just curious, is it possible at all to toggle the Fairy-Type in case we don't want it?

No, but like hacking any normal ROM, if you don't want to use something, then you just, well, don't use it! :P

Quote:

Originally Posted by Pia Carrot (Post 126299)
Sounds great, may even consider hacking again when this comes out.

Thanks, man.

I'll stick up some screenshots and a download link when I get home (if I remember! Haha).

Currently working on getting the music engine to produce wave sounds, so I'm getting reasonably close to finishing the first part of that.

The documentation I refer to will also be linked to once I've created it. Hope you guys appreciate the work going into this as much as I've enjoyed writing this thing! (The engine, not this post haha).

Team Fail 22nd October 2013 05:28 PM

Quote:

Originally Posted by Jambo51 (Post 126314)
No, but like hacking any normal ROM, if you don't want to use something, then you just, well, don't use it! :P

That could work. Change the typing so that nothing uses Fairy Type, and change the effectiveness table back to pre-Gen 6 settings.

I really like that you're using the M4A engine, since it's so usable everywhere anyways.

Linkandzelda 22nd October 2013 07:23 PM

This is really great to see this on there. I have an idea, perhaps have a config file that allows the selection of max generation to use? For example it could be configured to use only gen1, or up to gen6+. That way the amount of Pokémon and abilities could be tailored for what people want (and for example, make it have a GBC mode for gen2 games) and turning off Fairy type if you do add Kalos stuff.

Just a little idea, and really great to see this here!

Jambo51 22nd October 2013 07:59 PM

Quote:

Originally Posted by Linkandzelda (Post 126319)
This is really great to see this on there. I have an idea, perhaps have a config file that allows the selection of max generation to use? For example it could be configured to use only gen1, or up to gen6+. That way the amount of Pokémon and abilities could be tailored for what people want (and for example, make it have a GBC mode for gen2 games) and turning off Fairy type if you do add Kalos stuff.

Just a little idea, and really great to see this here!

I'd have to recompile the ROM several times, I'm not doing that. Since I'd just get confused about what's in one and not in another.

Like I said, if you don't want to use something, then just don't. All 649 Pokémon currently in it use their Gen 5 typings (so no fairies anywhere) but the type is there and has data in case people DO want to use it. Seem fair?

I'll also put in 2 separate Exp Calculations, one in gen 1-4 style, and one in gen 5 style.

Pia Carrot 22nd October 2013 08:59 PM

Just a couple questions.

How difficult would it be to change the screen resolution/size and how the textbox is positioned with your engine?

Also, will attacks be like they were before generation 4 or will they be split into Special and Physical individually?

Finally, so, like editing any normal ROM, I could use YAPE or something to change Pokémon typings and moves learned(if that's even still the modern tool to use, haven't hacked properly since 2010)?

Team Fail 22nd October 2013 09:06 PM

Quote:

Originally Posted by Pia Carrot (Post 126322)
Just a couple questions.

How difficult would it be to change the screen resolution/size and how the textbox is positioned with your engine?

Also, will attacks be like they were before generation 4 or will they be split into Special and Physical individually?

Finally, so, like editing any normal ROM, I could use YAPE or something to change Pokémon typings and moves learned(if that's even still the modern tool to use, haven't hacked properly since 2010)?

You never noticed that he's using either MaxMod or the M4A engine for music. Which implies he's making it as GBA homebrew using devkitarm. So your screen resolution will be that of the GBA itself.

Jambo51 22nd October 2013 09:09 PM

Quote:

Originally Posted by Pia Carrot (Post 126322)
Just a couple questions.

How difficult would it be to change the screen resolution/size and how the textbox is positioned with your engine?

Resolution and size are predetermined by the GBA, so no way of changing them.

Textbox positioning... I'm sure I can come up with some way of giving the hacker some form of control over it. I'll cross that bridge when I come to it! :P

Quote:

Originally Posted by Pia Carrot (Post 126322)
Also, will attacks be like they were before generation 4 or will they be split into Special and Physical individually?

They'll be split by default, using the new system.

Quote:

Originally Posted by Pia Carrot (Post 126322)
Finally, so, like editing any normal ROM, I could use YAPE or something to change Pokémon typings and moves learned(if that's even still the modern tool to use, haven't hacked properly since 2010)?

Yes, and no. Since I had to rearrange some of the data, some parts won't work properly inside existing editors.

For example, I reworked the base stats data to include extra information (like a hidden ability) and extend or remove other data from it. In general, I'm trying to stick to Game Freak's systems though.


All times are GMT. The time now is 10:47 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
User Alert System provided by Advanced User Tagging (Lite) - vBulletin Mods & Addons Copyright © 2017 DragonByte Technologies Ltd.
Pokémon characters and images belong to Pokémon USA, Inc. and Nintendo.
Pokémon Hackers Online (PHO) is in no way affiliated with or endorsed by Nintendo LLC, Creatures, GAMEFREAK inc,
The Pokémon Company, Pokémon USA, Inc., The Pokémon Company International, or Wizards of the Coast.
All forum/site content (unless noted otherwise) and site designs are © 2006-2013 Pokémon Hackers Online (PHO).

Green Charizard Christos TreeckoLv100