From 6e70c8f3488df57f38601a047beda34185072cea Mon Sep 17 00:00:00 2001 From: Squideo Kojima Date: Sat, 21 Nov 2015 12:08:14 -0800 Subject: [PATCH] Refactor metasprite organization Metasprites are now organized heirarchically, which should make adding new weapons considerably easier. All it takes to animate a charger is changing player_pwn[i] to WPN_CHARGER. Judd got pulled out into the new header file as well. --- game.c | 255 ++++----------------------------- metasprites.h | 386 ++++++++++++++++++++++++++++++++++++++++++++++++++ splatood.nes | Bin 40976 -> 40976 bytes 3 files changed, 412 insertions(+), 229 deletions(-) create mode 100644 metasprites.h diff --git a/game.c b/game.c index ee9f8e3..f7210a9 100644 --- a/game.c +++ b/game.c @@ -17,6 +17,9 @@ #include "levels/endgame.h" +/* Metasprite definitions */ +#include "metasprites.h" + /* Music data comes from music.s */ extern const unsigned char music_music_data[]; @@ -44,6 +47,16 @@ extern const unsigned char music_music_data[]; #define WALK_CYCLE 2 #define FRAMES_PER_STEP 10 +/* Sprite indices */ +#define SPR_DOWN 0 +#define SPR_RIGHT 1 +#define SPR_UP 2 +#define SPR_LEFT 3 + +/* Weapons */ +#define WPN_ROLLER 0 +#define WPN_CHARGER 1 + /* Tuneable gameplay parameters */ #define RESPAWN_TIME 64 #define PROJECTILE_WAIT_TIME 16 @@ -120,229 +133,6 @@ const unsigned char level_bluefin_depot[] = "Bluefin Depot"; const unsigned char level_saltspray[] = "Saltspray Rig"; const unsigned char level_twofish[] = "Two Fish"; -/* Meta sprites for players */ -/* DOWN, LEFT, RIGHT, UP */ -const unsigned char sprPlayerA1[][17]={ - { - 0,-1,0x40,0, - 8,-1,0x41,0, - 0, 7,0x50,0, - 8, 7,0x51,0, - 128 - }, - { - 0,-1,0x45,0|OAM_FLIP_H, - 8,-1,0x44,0|OAM_FLIP_H, - 0, 7,0x55,0|OAM_FLIP_H, - 8, 7,0x54,0|OAM_FLIP_H, - 128 - }, - { - 0,-1,0x44,0, - 8,-1,0x45,0, - 0, 7,0x54,0, - 8, 7,0x55,0, - 128 - }, - { - 0,-1,0x48,0, - 8,-1,0x49,0, - 0, 7,0x58,0, - 8, 7,0x59,0, - 128 - } -}; - -const unsigned char sprPlayerA2[][17]={ - { - 0,-1,0x42,0, - 8,-1,0x43,0, - 0, 7,0x52,0, - 8, 7,0x53,0, - 128 - }, - { - 0,-1,0x47,0|OAM_FLIP_H, - 8,-1,0x46,0|OAM_FLIP_H, - 0, 7,0x57,0|OAM_FLIP_H, - 8, 7,0x56,0|OAM_FLIP_H, - 128 - }, - { - 0,-1,0x46,0, - 8,-1,0x47,0, - 0, 7,0x56,0, - 8, 7,0x57,0, - 128 - }, - { - 0,-1,0x4a,0, - 8,-1,0x4b,0, - 0, 7,0x5a,0, - 8, 7,0x5b,0, - 128 - } -}; - -const unsigned char sprPlayerB1[][17]={ - { - 0,-1,0x40,1, - 8,-1,0x41,1, - 0, 7,0x50,1, - 8, 7,0x51,1, - 128 - }, - { - 0,-1,0x45,1|OAM_FLIP_H, - 8,-1,0x44,1|OAM_FLIP_H, - 0, 7,0x55,1|OAM_FLIP_H, - 8, 7,0x54,1|OAM_FLIP_H, - 128 - }, - { - 0,-1,0x44,1, - 8,-1,0x45,1, - 0, 7,0x54,1, - 8, 7,0x55,1, - 128 - }, - { - 0,-1,0x48,1, - 8,-1,0x49,1, - 0, 7,0x58,1, - 8, 7,0x59,1, - 128 - } -}; - -const unsigned char sprPlayerB2[][17]={ - { - 0,-1,0x42,1, - 8,-1,0x43,1, - 0, 7,0x52,1, - 8, 7,0x53,1, - 128 - }, - { - 0,-1,0x47,1|OAM_FLIP_H, - 8,-1,0x46,1|OAM_FLIP_H, - 0, 7,0x57,1|OAM_FLIP_H, - 8, 7,0x56,1|OAM_FLIP_H, - 128 - }, - { - 0,-1,0x46,1, - 8,-1,0x47,1, - 0, 7,0x56,1, - 8, 7,0x57,1, - 128 - }, - { - 0,-1,0x4a,1, - 8,-1,0x4b,1, - 0, 7,0x5a,1, - 8, 7,0x5b,1, - 128 - } -}; - - -/* Judd metasprites for post-game screen. */ -const unsigned char judd_left[] = { - 0,0,0x60,1, - 8,0,0x61,1, - 16,0,0x62,0, - 24,0,0x63,0, - 32,0,0x64,0, - - 0,8,0x70,1, - 8,8,0x71,1, - 16,8,0x72,0, - 24,8,0x73,0, - 32,8,0x74,0, - - 0,16,0x80,1, - 8,16,0x81,1, - 16,16,0x82,0, - 24,16,0x83,0, - 32,16,0x84,0, - - 0,24,0x90,1, - 8,24,0x91,1, - 16,24,0x92,0, - 24,24,0x93,0, - 32,24,0x94,0, - - 128, -}; - -const unsigned char judd_tie[] = { - 0,0,0x65,0, - 8,0,0x62,0, - 16,0,0x63,0, - 24,0,0x64,0, - - 0,8,0x75,0, - 8,8,0x72,0, - 16,8,0x73,0, - 24,8,0x74,0, - - 0,16,0x85,0, - 8,16,0x82,0, - 16,16,0x83,0, - 24,16,0x84,0, - - 0,24,0x95,0, - 8,24,0x92,0, - 16,24,0x93,0, - 24,24,0x94,0, - - 128, -}; - -const unsigned char judd_right[] = { - 32,0,0x60,2|OAM_FLIP_H, - 24,0,0x61,2|OAM_FLIP_H, - 16,0,0x62,0|OAM_FLIP_H, - 8,0,0x63,0|OAM_FLIP_H, - 0,0,0x64,0|OAM_FLIP_H, - - 32,8,0x70,2|OAM_FLIP_H, - 24,8,0x71,2|OAM_FLIP_H, - 16,8,0x72,0|OAM_FLIP_H, - 8,8,0x73,0|OAM_FLIP_H, - 0,8,0x74,0|OAM_FLIP_H, - - 32,16,0x80,2|OAM_FLIP_H, - 24,16,0x81,2|OAM_FLIP_H, - 16,16,0x82,0|OAM_FLIP_H, - 8,16,0x83,0|OAM_FLIP_H, - 0,16,0x84,0|OAM_FLIP_H, - - 32,24,0x90,2|OAM_FLIP_H, - 24,24,0x91,2|OAM_FLIP_H, - 16,24,0x92,0|OAM_FLIP_H, - 8,24,0x93,0|OAM_FLIP_H, - 0,24,0x94,0|OAM_FLIP_H, - - 128, -}; - -/* Metasprite sets. */ -const unsigned char* const sprListPlayerDown[]={ - sprPlayerA1[0],sprPlayerA2[0],sprPlayerB1[0],sprPlayerB2[0] -}; -const unsigned char* const sprListPlayerLeft[]={ - sprPlayerA1[1],sprPlayerA2[1],sprPlayerB1[1],sprPlayerB2[1] -}; -const unsigned char* const sprListPlayerRight[]={ - sprPlayerA1[2],sprPlayerA2[2],sprPlayerB1[2],sprPlayerB2[2] -}; -const unsigned char* const sprListPlayerUp[]={ - sprPlayerA1[3],sprPlayerA2[3],sprPlayerB1[3],sprPlayerB2[3] -}; - - /* Level count */ #define LEVELS_ALL 4 @@ -399,6 +189,7 @@ static unsigned char player_wait [PLAYER_MAX]; static unsigned char player_cooldown [PLAYER_MAX]; static unsigned char player_anim_cnt [PLAYER_MAX]; static unsigned char player_diag_flip[PLAYER_MAX]; +static unsigned char player_wpn [PLAYER_MAX]; static unsigned int projectile_x [PLAYER_MAX]; static unsigned int projectile_y [PLAYER_MAX]; @@ -413,7 +204,8 @@ static unsigned char game_done; static unsigned char game_paused; static unsigned char frame_cnt; -static unsigned char anim_index; +static unsigned char anim_frame; +static unsigned char spr_dir; static unsigned char bright; static unsigned char timer; @@ -1092,6 +884,8 @@ void game_loop(void) { player_wait [player_all] = 16+((spr-TILE_PLAYERA)<<4); player_cooldown [player_all] = 0; player_speed [player_all] = 2<>FP_BITS; - anim_index = i * WALK_CYCLE + (player_anim_cnt[i] / FRAMES_PER_STEP) % WALK_CYCLE; + anim_frame = (player_anim_cnt[i] / FRAMES_PER_STEP) % WALK_CYCLE; switch (player_dir[i]) { case DIR_NONE: - case DIR_DOWN: oam_meta_spr(px,py,spr,sprListPlayerDown[anim_index]); break; - case DIR_LEFT: oam_meta_spr(px,py,spr,sprListPlayerLeft[anim_index]); break; - case DIR_RIGHT: oam_meta_spr(px,py,spr,sprListPlayerRight[anim_index]); break; - case DIR_UP: oam_meta_spr(px,py,spr,sprListPlayerUp[anim_index]); break; + case DIR_DOWN: spr_dir = SPR_DOWN; break; + case DIR_LEFT: spr_dir = SPR_LEFT; break; + case DIR_RIGHT: spr_dir = SPR_RIGHT; break; + case DIR_UP: spr_dir = SPR_UP; break; } + oam_meta_spr( + px, py, spr, SprPlayers[i][player_wpn[i]][spr_dir][anim_frame], + ); spr-=16; } diff --git a/metasprites.h b/metasprites.h new file mode 100644 index 0000000..5ddbf7a --- /dev/null +++ b/metasprites.h @@ -0,0 +1,386 @@ +/* Player metaprites! + * Player metasprites are organized as: + * SprPlayers[player number][player weapon][player direction][animation frame] + * Player weapons are ordered ROLLER CHARGER (see WPN_ROLLER, etc in game.c) + * Player directions need to be ordered DOWN RIGHT UP LEFT (see SPR_DOWN, etc in game.c) + */ +const unsigned char SprPlayer1RollerDownFrame1[] = { + 0,-1,0x40,0, + 8,-1,0x41,0, + 0, 7,0x50,0, + 8, 7,0x51,0, + 128 +}; + +const unsigned char SprPlayer1RollerDownFrame2[] = { + 0,-1,0x42,0, + 8,-1,0x43,0, + 0, 7,0x52,0, + 8, 7,0x53,0, + 128 +}; + +const unsigned char* const SprPlayer1RollerDown[] = {SprPlayer1RollerDownFrame1, SprPlayer1RollerDownFrame2}; + +const unsigned char SprPlayer1RollerRightFrame1[] = { + 0,-1,0x44,0, + 8,-1,0x45,0, + 0, 7,0x54,0, + 8, 7,0x55,0, + 128 +}; + +const unsigned char SprPlayer1RollerRightFrame2[] = { + 0,-1,0x46,0, + 8,-1,0x47,0, + 0, 7,0x56,0, + 8, 7,0x57,0, + 128 +}; + +const unsigned char* const SprPlayer1RollerRight[] = {SprPlayer1RollerRightFrame1, SprPlayer1RollerRightFrame2}; + +const unsigned char SprPlayer1RollerUpFrame1[] = { + 0,-1,0x48,0, + 8,-1,0x49,0, + 0, 7,0x58,0, + 8, 7,0x59,0, + 128 +}; + +const unsigned char SprPlayer1RollerUpFrame2[] = { + 0,-1,0x4a,0, + 8,-1,0x4b,0, + 0, 7,0x5a,0, + 8, 7,0x5b,0, + 128 +}; + +const unsigned char* const SprPlayer1RollerUp[] = {SprPlayer1RollerUpFrame1, SprPlayer1RollerUpFrame2}; + +const unsigned char SprPlayer1RollerLeftFrame1[] = { + 0,-1,0x45,0|OAM_FLIP_H, + 8,-1,0x44,0|OAM_FLIP_H, + 0, 7,0x55,0|OAM_FLIP_H, + 8, 7,0x54,0|OAM_FLIP_H, + 128 +}; + +const unsigned char SprPlayer1RollerLeftFrame2[] = { + 0,-1,0x47,0|OAM_FLIP_H, + 8,-1,0x46,0|OAM_FLIP_H, + 0, 7,0x57,0|OAM_FLIP_H, + 8, 7,0x56,0|OAM_FLIP_H, + 128 +}; + +const unsigned char* const SprPlayer1RollerLeft[] = {SprPlayer1RollerLeftFrame1, SprPlayer1RollerLeftFrame2}; + +const unsigned char* const * const SprPlayer1Roller[] = {SprPlayer1RollerDown, SprPlayer1RollerRight, SprPlayer1RollerUp, SprPlayer1RollerLeft}; + +const unsigned char SprPlayer1ChargerDownFrame1[] = { + 0,-1,0x00,0, + 8,-1,0x01,0, + 0, 7,0x10,0, + 8, 7,0x11,0, + 128 +}; + +const unsigned char SprPlayer1ChargerDownFrame2[] = { + 0,-1,0x02,0, + 8,-1,0x03,0, + 0, 7,0x12,0, + 8, 7,0x13,0, + 128 +}; + +const unsigned char* const SprPlayer1ChargerDown[] = {SprPlayer1ChargerDownFrame1, SprPlayer1ChargerDownFrame2}; + +const unsigned char SprPlayer1ChargerRightFrame1[] = { + 0,-1,0x04,0, + 8,-1,0x05,0, + 0, 7,0x14,0, + 8, 7,0x15,0, + 128 +}; + +const unsigned char SprPlayer1ChargerRightFrame2[] = { + 0,-1,0x06,0, + 8,-1,0x07,0, + 0, 7,0x16,0, + 8, 7,0x17,0, + 128 +}; + +const unsigned char* const SprPlayer1ChargerRight[] = {SprPlayer1ChargerRightFrame1, SprPlayer1ChargerRightFrame2}; + +const unsigned char SprPlayer1ChargerUpFrame1[] = { + 0,-1,0x08,0, + 8,-1,0x09,0, + 0, 7,0x18,0, + 8, 7,0x19,0, + 128 +}; + +const unsigned char SprPlayer1ChargerUpFrame2[] = { + 0,-1,0x0a,0, + 8,-1,0x0b,0, + 0, 7,0x1a,0, + 8, 7,0x1b,0, + 128 +}; + +const unsigned char* const SprPlayer1ChargerUp[] = {SprPlayer1ChargerUpFrame1, SprPlayer1ChargerUpFrame2}; + +const unsigned char SprPlayer1ChargerLeftFrame1[] = { + 0,-1,0x05,0|OAM_FLIP_H, + 8,-1,0x04,0|OAM_FLIP_H, + 0, 7,0x15,0|OAM_FLIP_H, + 8, 7,0x14,0|OAM_FLIP_H, + 128 +}; + +const unsigned char SprPlayer1ChargerLeftFrame2[] = { + 0,-1,0x07,0|OAM_FLIP_H, + 8,-1,0x06,0|OAM_FLIP_H, + 0, 7,0x17,0|OAM_FLIP_H, + 8, 7,0x16,0|OAM_FLIP_H, + 128 +}; + +const unsigned char* const SprPlayer1ChargerLeft[] = {SprPlayer1ChargerLeftFrame1, SprPlayer1ChargerLeftFrame2}; + +const unsigned char* const * const SprPlayer1Charger[] = {SprPlayer1ChargerDown, SprPlayer1ChargerRight, SprPlayer1ChargerUp, SprPlayer1ChargerLeft}; +const unsigned char* const * const * const SprPlayer1[] = {SprPlayer1Roller, SprPlayer1Charger}; + +const unsigned char SprPlayer2RollerDownFrame1[] = { + 0,-1,0x40,1, + 8,-1,0x41,1, + 0, 7,0x50,1, + 8, 7,0x51,1, + 128 +}; + +const unsigned char SprPlayer2RollerDownFrame2[] = { + 0,-1,0x42,1, + 8,-1,0x43,1, + 0, 7,0x52,1, + 8, 7,0x53,1, + 128 +}; + +const unsigned char* const SprPlayer2RollerDown[] = {SprPlayer2RollerDownFrame1, SprPlayer2RollerDownFrame2}; + +const unsigned char SprPlayer2RollerRightFrame1[] = { + 0,-1,0x44,1, + 8,-1,0x45,1, + 0, 7,0x54,1, + 8, 7,0x55,1, + 128 +}; + +const unsigned char SprPlayer2RollerRightFrame2[] = { + 0,-1,0x46,1, + 8,-1,0x47,1, + 0, 7,0x56,1, + 8, 7,0x57,1, + 128 +}; + +const unsigned char* const SprPlayer2RollerRight[] = {SprPlayer2RollerRightFrame1, SprPlayer2RollerRightFrame2}; + +const unsigned char SprPlayer2RollerUpFrame1[] = { + 0,-1,0x48,1, + 8,-1,0x49,1, + 0, 7,0x58,1, + 8, 7,0x59,1, + 128 +}; + +const unsigned char SprPlayer2RollerUpFrame2[] = { + 0,-1,0x4a,1, + 8,-1,0x4b,1, + 0, 7,0x5a,1, + 8, 7,0x5b,1, + 128 +}; + +const unsigned char* const SprPlayer2RollerUp[] = {SprPlayer2RollerUpFrame1, SprPlayer2RollerUpFrame2}; + +const unsigned char SprPlayer2RollerLeftFrame1[] = { + 0,-1,0x45,1|OAM_FLIP_H, + 8,-1,0x44,1|OAM_FLIP_H, + 0, 7,0x55,1|OAM_FLIP_H, + 8, 7,0x54,1|OAM_FLIP_H, + 128 +}; + +const unsigned char SprPlayer2RollerLeftFrame2[] = { + 0,-1,0x47,1|OAM_FLIP_H, + 8,-1,0x46,1|OAM_FLIP_H, + 0, 7,0x57,1|OAM_FLIP_H, + 8, 7,0x56,1|OAM_FLIP_H, + 128 +}; + +const unsigned char* const SprPlayer2RollerLeft[] = {SprPlayer2RollerLeftFrame1, SprPlayer2RollerLeftFrame2}; + +const unsigned char* const * const SprPlayer2Roller[] = {SprPlayer2RollerDown, SprPlayer2RollerRight, SprPlayer2RollerUp, SprPlayer2RollerLeft}; + +const unsigned char SprPlayer2ChargerDownFrame1[] = { + 0,-1,0x00,1, + 8,-1,0x01,1, + 0, 7,0x10,1, + 8, 7,0x11,1, + 128 +}; + +const unsigned char SprPlayer2ChargerDownFrame2[] = { + 0,-1,0x02,1, + 8,-1,0x03,1, + 0, 7,0x12,1, + 8, 7,0x13,1, + 128 +}; + +const unsigned char* const SprPlayer2ChargerDown[] = {SprPlayer2ChargerDownFrame1, SprPlayer2ChargerDownFrame2}; + +const unsigned char SprPlayer2ChargerRightFrame1[] = { + 0,-1,0x04,1, + 8,-1,0x05,1, + 0, 7,0x14,1, + 8, 7,0x15,1, + 128 +}; + +const unsigned char SprPlayer2ChargerRightFrame2[] = { + 0,-1,0x06,1, + 8,-1,0x07,1, + 0, 7,0x16,1, + 8, 7,0x17,1, + 128 +}; + +const unsigned char* const SprPlayer2ChargerRight[] = {SprPlayer2ChargerRightFrame1, SprPlayer2ChargerRightFrame2}; + +const unsigned char SprPlayer2ChargerUpFrame1[] = { + 0,-1,0x08,1, + 8,-1,0x09,1, + 0, 7,0x18,1, + 8, 7,0x19,1, + 128 +}; + +const unsigned char SprPlayer2ChargerUpFrame2[] = { + 0,-1,0x0a,1, + 8,-1,0x0b,1, + 0, 7,0x1a,1, + 8, 7,0x1b,1, + 128 +}; + +const unsigned char* const SprPlayer2ChargerUp[] = {SprPlayer2ChargerUpFrame1, SprPlayer2ChargerUpFrame2}; + +const unsigned char SprPlayer2ChargerLeftFrame1[] = { + 0,-1,0x05,1|OAM_FLIP_H, + 8,-1,0x04,1|OAM_FLIP_H, + 0, 7,0x15,1|OAM_FLIP_H, + 8, 7,0x14,1|OAM_FLIP_H, + 128 +}; + +const unsigned char SprPlayer2ChargerLeftFrame2[] = { + 0,-1,0x07,1|OAM_FLIP_H, + 8,-1,0x06,1|OAM_FLIP_H, + 0, 7,0x17,1|OAM_FLIP_H, + 8, 7,0x16,1|OAM_FLIP_H, + 128 +}; + +const unsigned char* const SprPlayer2ChargerLeft[] = {SprPlayer2ChargerLeftFrame1, SprPlayer2ChargerLeftFrame2}; + +const unsigned char* const * const SprPlayer2Charger[] = {SprPlayer2ChargerDown, SprPlayer2ChargerRight, SprPlayer2ChargerUp, SprPlayer2ChargerLeft}; +const unsigned char* const * const * const SprPlayer2[] = {SprPlayer2Roller, SprPlayer2Charger}; + +const unsigned char* const * const * const * const SprPlayers[] = {SprPlayer1, SprPlayer2}; + +/* Judd metasprites for post-game screen. */ +const unsigned char judd_left[] = { + 0,0,0x60,1, + 8,0,0x61,1, + 16,0,0x62,0, + 24,0,0x63,0, + 32,0,0x64,0, + + 0,8,0x70,1, + 8,8,0x71,1, + 16,8,0x72,0, + 24,8,0x73,0, + 32,8,0x74,0, + + 0,16,0x80,1, + 8,16,0x81,1, + 16,16,0x82,0, + 24,16,0x83,0, + 32,16,0x84,0, + + 0,24,0x90,1, + 8,24,0x91,1, + 16,24,0x92,0, + 24,24,0x93,0, + 32,24,0x94,0, + + 128, +}; + +const unsigned char judd_tie[] = { + 0,0,0x65,0, + 8,0,0x62,0, + 16,0,0x63,0, + 24,0,0x64,0, + + 0,8,0x75,0, + 8,8,0x72,0, + 16,8,0x73,0, + 24,8,0x74,0, + + 0,16,0x85,0, + 8,16,0x82,0, + 16,16,0x83,0, + 24,16,0x84,0, + + 0,24,0x95,0, + 8,24,0x92,0, + 16,24,0x93,0, + 24,24,0x94,0, + + 128, +}; + +const unsigned char judd_right[] = { + 32,0,0x60,2|OAM_FLIP_H, + 24,0,0x61,2|OAM_FLIP_H, + 16,0,0x62,0|OAM_FLIP_H, + 8,0,0x63,0|OAM_FLIP_H, + 0,0,0x64,0|OAM_FLIP_H, + + 32,8,0x70,2|OAM_FLIP_H, + 24,8,0x71,2|OAM_FLIP_H, + 16,8,0x72,0|OAM_FLIP_H, + 8,8,0x73,0|OAM_FLIP_H, + 0,8,0x74,0|OAM_FLIP_H, + + 32,16,0x80,2|OAM_FLIP_H, + 24,16,0x81,2|OAM_FLIP_H, + 16,16,0x82,0|OAM_FLIP_H, + 8,16,0x83,0|OAM_FLIP_H, + 0,16,0x84,0|OAM_FLIP_H, + + 32,24,0x90,2|OAM_FLIP_H, + 24,24,0x91,2|OAM_FLIP_H, + 16,24,0x92,0|OAM_FLIP_H, + 8,24,0x93,0|OAM_FLIP_H, + 0,24,0x94,0|OAM_FLIP_H, + + 128, +}; diff --git a/splatood.nes b/splatood.nes index 77eb23149a46f2f8f2856cec3f5f436a8c9189c5..0433f0fb8b71aa3d465be2ad80407205a064228f 100644 GIT binary patch delta 9608 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