More Sprites
More Sprites v1.1.4
by AboodXD, updated by CLF78, Nin0, Synel, and Ryguy
Original code can be found on the New Super Mario Lost Worlds repo
Note
NSMBWer+ already comes packaged with more sprites. You do not need to install it unless using NewerSMBW as a base.
Kamek
- Add
include/asm_setup.Sin yourincludefolder - Add
src/profile.cppin yoursrcfolder - Add
include/profileid.hin yourincludefolder - Add
src/profile.Sin yoursrcfolder - Add
profile.yamlin yourKamekfolder - Replace
kamek_configs.yamlin yourKamekfolder - Add
include/profile.hin yourincludefolder - Add
include/asm_profiles.Sin yourincludefolder - Don't forget to reference
profile.yamlinNewerProject.yamlor whatever file you use to compile - Add these addresses to your
kamek_pal.x:
originalSprites = 0x8030a340;
originalProfiles = 0x8076a748;
ObjectProfileList = 0x8042a698;
spriteFiles = 0x8031ab4c;
profileNames = 0x80320b58;
searchByProfileId__7fBase_cFUsP7fBase_c = 0x80162E90;
create__13dStageActor_cFUsUiP7Point3dP6S16VecUc = 0x80064610;
createChild__13dStageActor_cFUsP13dStageActor_cUiP7Point3dP6S16VecUc = 0x80064680;- In your
include/game.h, replace this line in thefBase_cclass:
u16 name;with this:
union {
u16 name;
u16 profileId;
};- In your
include/game.h, add this line under thestatic fBase_c *search(u32 id);line:
static fBase_c *searchByProfileId(u16 profileId, fBase_c *previous = 0);- In your
include/game.h, add this line under thestatic dStageActor_c *createChild(Actors type, dStageActor_c *parent, u32 settings, Vec *pos, S16Vec *rot, u8 layer);line:
static dStageActor_c *create(u16 type, u32 settings, Vec *pos, S16Vec *rot, u8 layer);
static dStageActor_c *createChild(u16 type, dStageActor_c *parent, u32 settings, Vec *pos, S16Vec *rot, u8 layer);- In your
tools/kamek.py, replace these lines:
for d in self._config.get('defines', []) + self.project.data.get('defines', []):
cc_command.append('-d')
cc_command.append(d)
as_command.append('-d')
as_command.append(d)
print(f'defined: {d}')with this:
if 'defines' in self._config:
for d in self._config['defines']:
cc_command.append('-d')
cc_command.append(d)
as_command.append('-d')
as_command.append(d)- Compile your code
Note that this code will not compile until you add your first new sprite, due to the list being empty if no custom sprites are found.
Add a new sprite
Let's say you want to add a sprite with a class named dMySprite_c in a file named mySprite.cpp with a filelist named MySpriteFileList.
First thing first, your YAML file should look like this:
---
source_files: [../src/mySprite.cpp]
hooks: []As you can see, we don't have any hooks, because we don't need any. We're just adding a new sprite, not modifying an existing one.
PS: Don't forget to reference your YAML to NewerProject.yaml or whatever file you use to compile, below profile.yaml
Open src/profileid.h. There should be a // Start of custom entries line and a Beginning of new entries.
The first one is for sprite IDs, the second one is for actor IDs.
Let's choose a name for our new sprite. Because our class name is dMySprite_c, let's call it MySprite. This name is our sprite name.
Make sure the name doesn't contain any spaces or special characters and doesn't exist yet in both lists.
Go to the end of the sprite IDs list and get the last sprite ID of the list. In this case, because we never added a sprite before, it's AC_BOSS_KOOPA_BG_EFFECT = 482, so its sprite ID is 482. So, our sprite ID will be 483 (482 + 1).
So let's add our sprite ID to the list by adding this line:
MySprite = 483,so the end of the list should look like this:
AC_BOSS_KOOPA_BG_EFFECT = 482,
// Start of custom entries
MySprite = 483,
Num
};Now, let's add the actor ID. Go to the end of the actor IDs list and get the last actor ID of the list. In this case, because we never added an actor before, it's LASTACTOR, // 749 so its actor ID is 749. So, our actor ID will be 750 (749 + 1).
NOTE: because the actor IDs differ between game versions, we cannot assign a static value to the actor in the list. Use comments to keep track of actor IDs instead.
So let's add our actor ID to the list by adding this line:
MySprite, // 750so the end of the list should look like this:
LASTACTOR, // 749
// Beginning of new entries
MySprite, // 750
Num
};Now, let's reference our new actor ID to the asm_profiles.S list. Open include/asm_profiles.S.
Go to the end of the file and add this line by replace WWWWWW with your sprite name and XXX with your actor ID:
#define WWWWWW PROFILEID_ADJUST_C+PROFILEID_ADJUST_KW+XXXIn our case, our sprite name is MySprite and our actor ID is 750, so we'll add this line:
#define MySprite PROFILEID_ADJUST_C+PROFILEID_ADJUST_KW+750so in our case the end of the file should look like this:
#define LASTACTOR_STAGE PROFILEID_ADJUST_C+PROFILEID_ADJUST_KW+748
#define LASTACTOR PROFILEID_ADJUST_C+PROFILEID_ADJUST_KW+749
#define MySprite PROFILEID_ADJUST_C+PROFILEID_ADJUST_KW+750Now, let's configure the sprite. Open your sprite filename, in our case, it's src/mySprite.cpp.
First, we need to change the build method as it only accepts dActor_c* as an argument. We need to change both the method declaration and the method definition.
For the method declaration, change this:
public: static dMySprite_c *build();to this:
public: static dActor_c *build();Make sure the method is public and static.
For the method definition, change this:
dMySprite_c *dMySprite_c::build() {
void *buffer = AllocFromGameHeap1(sizeof(dMySprite_c));
return new(buffer) dMySprite_c;
}to this:
dActor_c *dMySprite_c::build() {
void *buffer = AllocFromGameHeap1(sizeof(dMySprite_c));
return new(buffer) dMySprite_c;
}Now, let's configure the sprite. Just below the method definition, add this:
const SpriteData MySpriteSpriteData = { ProfileId::MySprite, 8, -8, 0, 0, 0x100, 0x100, 0, 0, 0, 0, 0 };
Profile MySpriteProfile(&dMySprite_c::build, SpriteId::MySprite, &MySpriteSpriteData, ProfileId::MySprite, ProfileId::MySprite, "MySprite", MySpriteFileList, 0);Make sure to replace every MySprite with your sprite name and MySpriteFileList with your filelist name.
Let's explain what each SpriteData value means, from left to right:
const SpriteData MySpriteSpriteData = { ProfileId::MySprite, 8, -8, 0, 0, 0x100, 0x100, 0, 0, 0, 0, 0 };ProfileId::MySprite: The actor ID of the sprite. It's the same as the actor ID we added toprofileid.h(the750).8: The sprite's position offset on the X axis.-8: The sprite's position offset on the Y axis.0: The spawn range offset on the X axis.0: The spawn range offset on the Y axis.0x100: The sprite range size on the X axis.0x100: The sprite range size on the Y axis.0: Don't know what it does, leave it at 0.0: Don't know what it does, leave it at 0.0: Don't know what it does, leave it at 0.0: Don't know what it does, leave it at 0.0: The spawning flags. Don't know the values, so you can leave it at 0.
Now, let's explain what each Profile value means, from left to right:
Profile MySpriteProfile(&dMySprite_c::build, SpriteId::MySprite, &MySpriteSpriteData, ProfileId::MySprite, ProfileId::MySprite, "MySprite", MySpriteFileList, 0);&dMySprite_c::build: The build method of the sprite. It's the same as the method we changed earlier.SpriteId::MySprite: The sprite ID of the sprite. It's the same as the sprite ID we added toprofileid.h(the483).&MySpriteSpriteData: The sprite data of the sprite. It's the reference to the SpriteData we created earlier.ProfileId::MySprite: The execution order of the sprite. It's the same as the actor ID we added toprofileid.h(the750) but can be different if needed. If you're using a Physics variable that needs to move objects with it, change this execution order toProfileId::EN_SLIP_PENGUIN.ProfileId::MySprite: The drawing order of the sprite. It's the same as the actor ID we added toprofileid.h(the750) but can be different if needed."MySprite": The name of the sprite. It's the same as the sprite name we added toprofileid.h(theMySprite).MySpriteFileList: The filelist of the sprite.0: Actor flags. Here are the different flags you can add:0x2: Unknown, several profiles have this set0x4: Unknown, never used0x8: Makes Mario look at the actor0x10: Killed by level clear and awards score0x20: Killed by level clear0x40: Only set on balloons ? (Not sure)0x80: Can be killed by iceballs (magic e.g. podoboos)0x200: Bounces Penguin Mario back when sliding into the actor0x400: Ignores wrap around edges
You can then compile your code and enjoy !