Change your Player's Appearance/Weapons [4.5.6] [Intermediate]

JamesNES

Well-known member
So, I wanted to have my player get different sets of armour/weapons during the game, but found myself quickly out of space in the standard game objects graphics set. I thought about palette swapping but that seemed pretty boring. I came up with this way to just instead swap out strips of the game object CHR which is fast and takes up very little space.

What you'll need is two variables, one for determining which set of graphics to use for the player and one for which set to use for the weapons, I've called them:

playerArmour
playerWeapon

What my idea basically is, is that you have all your player sprites in two rows of 8 pixel sprites at the top of the file, then your weapons in the next two rows, and during screenload you can swap them out depending on what those two variables hold. For reference:

GameObjectTiles.png

Player in the top row, weapon (in this picture a staff) on the second row.

Next, you need to add the graphics that will be swapped in.

Separate them out into strips like this:

player0.png

weapons0.png

and your new player/weapon sprites:

player1.png

weapons1.png

For these, you need to convert them to .chr and put them in NESMaker\GameData\Graphics\Sprites. This is easy, NESMaker has a built in CHR converter.

pixel editor.png

Save them all in that directory as .chr files. Give them names like "CHR_PlayerSprites_00" and "CHR_WeaponSprites_00".

We'll include the new graphics in bank 15 as that is where the normal game objects graphics lives, and it's basically entirely empty.

So open up Bank15.asm and add this, making sure your filenames are correct:

Code:
PlayerSpriteTiles00:
	.incbin "Graphics\Sprites\CHR_PlayerSprites_00.chr"
	
PlayerSpriteTiles01:
	.incbin "Graphics\Sprites\CHR_PlayerSprites_01.chr"
	
WeaponObjectTiles00:
	.incbin "Graphics\Sprites\CHR_WeaponSprites_00.chr"
	
WeaponObjectTiles01:
	.incbin "Graphics\Sprites\CHR_WeaponSprites_01.chr"

Each of these files takes up about 3% of the bank, so it's pretty cheap considering how nifty it is.

Next we make references to these in Bank16.asm. Around line 410 there's the address for the standard game objects CHR so that's a good spot to put these under:

Code:
PlayerSpriteCHRAddLo:
	.db <PlayerSpriteTiles00, <PlayerSpriteTiles01
	
PlayerSpriteCHRAddHi:
	.db >PlayerSpriteTiles00, >PlayerSpriteTiles01

WeaponObjectCHRAddLo:
	.db <WeaponObjectTiles00, <WeaponObjectTiles01
	
WeaponObjectCHRAddHi:
	.db >WeaponObjectTiles00, >WeaponObjectTiles01

Finally, we have to get them to actually load. With this method it will only happen when the screen is reloaded. This is done in DoLoadScreen.asm.

Around line 380 you'll see:

Code:
doneLoadingChrs:
		
		
		
		
	LoadChrData #$15, #$00, #$00, #$80, GameObjectCHRAddLo, GameObjectCHRAddHi, #$00
		;arg0 - bank where graphics live
		;arg1 - row
		;arg2 - column (by 10s...must end in zero)
		;arg3 - how many tiles to load.  If 00, will load whole sheet.
		;arg4 - Label in bank 16 table, low.
		;arg5 - Label in bank 16 table, hi.
		;arg6 - Bank 16 table offset

Immediately after this, we want to add this, to replace the first 4 rows of game object data that just loaded:

Code:
		LoadChrData #$15, #$00, #$00, #$20, PlayerSpriteCHRAddLo, PlayerSpriteCHRAddHi, playerArmour
		

		LoadChrData #$15, #$02, #$00, #$20, WeaponObjectCHRAddLo, WeaponObjectCHRAddHi, playerWeapon

So what this does, is change which player sprites and weapon sprites are loaded based on those two variables. At the moment the only two options are 0 or 1 so anything other value will give garbage results.

Tada:

howto.gif

(You can also change the sprite palette to match the new sprites).
 

Jonny

Well-known member
Nice work. Am I understanding this correctly, so could you have a tile with...

Less:
LDA #$01
STA playerArmour

... and that would change the graphics? or would it need to update / load a new screen?
 

JamesNES

Well-known member
Nice work. Am I understanding this correctly, so could you have a tile with...

Less:
LDA #$01
STA playerArmour

... and that would change the graphics? or would it need to update / load a new screen?

This way it only changes when you move to a new screen (or reload by warping to the same spot). I'm using it when the player talks to an NPC, it changes the armour value and reloads by warping.
 

Jonny

Well-known member
Isn't there something similar to this built in for weapons? I don't know weather to bother reading up on that or just use this way. I really like this method.

If there was a fancy flash effect on screen load (i.e make screen white) it would look awesome. The warp would have to be quite different for scrolling games, to save the screen and player position first not just a general warptoscreen. Love it, going to try it out.
 

JamesNES

Well-known member
It's easy to set the weapon to be created to be a different object, but then you need to use up space in the objects tile set for each weapon, waste one of the 16 game object slots etc.

With warping, you can use the third argument in the WarpToScreen macro to set a "warp type" which is checked in doLoadScreenData. There you can just skip setting newX/newY if it's a screen-reload type so the player's X and Y will stay the same. After this bit:

Code:
;=======================================
;; 128 - Warp In Position
;; This might need to be skipped under certain warp conditions
;; and should only be observed if the transition is of warp type.

	LDA screenTransitionType
	BNE +continue 
		JMP skipSettingWarpInXY
	+continue
	CMP #$01
	BEQ setToStartValue
	CMP #$02
	BEQ setToContinueValue
		;;; other cases go here

Haven't done much with the scrolling stuff myself so I'm not sure how the scroll is affected by warping.
 

JamesNES

Well-known member
Nice work. Am I understanding this correctly, so could you have a tile with...

Less:
LDA #$01
STA playerArmour

... and that would change the graphics? or would it need to update / load a new screen?

Thought about this again, and it works just fine if you turn off rendering for a split second, load the graphics, then turn it on again. So you can make a subroutine like this and call it from anywhere. If you don't turn off rendering the background tiles glitch out until you load a new screen.

Code:
loadNewGraphics:
    LDA #$00
    STA $2001
    LoadChrData #$15, #$02, #$00, #$20, WeaponObjectCHRAddLo, WeaponObjectCHRAddHi, playerWeapon
    LoadChrData #$15, #$00, #$00, #$20, PlayerSpriteCHRAddLo, PlayerSpriteCHRAddHi, playerArmour
    LDA #%00011110
    STA $2001
    RTS
 

mouse spirit

Well-known member
Im trying to use this to 4.1.5. but im getting an error for bankassign.asm line 116. Trying to include bank 16.
 
Last edited:

Jonny

Well-known member
Thought about this again, and it works just fine if you turn off rendering for a split second, load the graphics, then turn it on again. So you can make a subroutine like this and call it from anywhere. If you don't turn off rendering the background tiles glitch out until you load a new screen.

Code:
loadNewGraphics:
    LDA #$00
    STA $2001
    LoadChrData #$15, #$02, #$00, #$20, WeaponObjectCHRAddLo, WeaponObjectCHRAddHi, playerWeapon
    LoadChrData #$15, #$00, #$00, #$20, PlayerSpriteCHRAddLo, PlayerSpriteCHRAddHi, playerArmour
    LDA #%00011110
    STA $2001
    RTS

Just got around to trying this (but for entire ObjectTiles change). I still got the background crazyness on single screen. For scrolling sections game crashed but that was probably expected. Doing a warp works fine and that might be the best I'll get. I was hoping for something a little smoother so a gun is collected and graphics change to suit but I think I'm asking a little too much with that!
 

JamesNES

Well-known member
Just got around to trying this (but for entire ObjectTiles change). I still got the background crazyness on single screen. For scrolling sections game crashed but that was probably expected. Doing a warp works fine and that might be the best I'll get. I was hoping for something a little smoother so a gun is collected and graphics change to suit but I think I'm asking a little too much with that!
Weird, mine is only changing two rows, maybe that's the difference? Just using the code to turn off rendering I posted. Haven't tried changing the palettes at the same time yet though:
 

Attachments

  • armourswitch.gif
    armourswitch.gif
    60.1 KB · Views: 10

Jonny

Well-known member
Weird, mine is only changing two rows, maybe that's the difference? Just using the code to turn off rendering I posted. Haven't tried changing the palettes at the same time yet though:
Possibly not enough time to change the entire game objects tileset I guess. I'll try changing 2 rows only and see if I get the same. If not, I'll just work it into the game design. Getting a weapon at the end of a boss fight as a reward would work.
 
Top Bottom