Add shield

This commit is contained in:
Lucas S. Vieira 2024-11-12 19:34:17 -03:00
parent 2b1f52cdb6
commit 5b35c90259
16 changed files with 118 additions and 43 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

@ -396,6 +396,22 @@ duration = 2
frames = [[216, 16, 16, 16]]
loopback = 0
# ============
[shield]
[[shield.animations]]
id = 0
name = "default"
duration = 4
frames = [
[50, 200, 48, 48],
[98, 200, 48, 48],
[50, 200, 48, 48, 1, 0],
[98, 200, 48, 48],
]
loopback = 0
# ============
# Dummy objects
# ============

View file

@ -51,4 +51,5 @@
<tile id="12" type="startpos"/>
<tile id="13" type="explosion"/>
<tile id="14" type="monitor_image"/>
<tile id="15" type="shield"/>
</tileset>

BIN
assets/sfx/SHIELD.ogg Normal file

Binary file not shown.

BIN
assets/sfx/SKIDDING.ogg Normal file

Binary file not shown.

Binary file not shown.

View file

@ -6,8 +6,8 @@ for f in *.ogg; do
rm "${f%%.ogg}.WAV";
done
for f in *.wav; do
ffmpeg -y -i "$f" -acodec pcm_s16le -ac 1 -ar 22050 "${f%%.wav}_2.WAV";
wav2vag "${f%%.wav}_2.WAV" "${f%%.wav}.VAG";
rm "${f%%.wav}_2.WAV";
done
# for f in *.wav; do
# ffmpeg -y -i "$f" -acodec pcm_s16le -ac 1 -ar 22050 "${f%%.wav}_2.WAV";
# wav2vag "${f%%.wav}_2.WAV" "${f%%.wav}.VAG";
# rm "${f%%.wav}_2.WAV";
# done

View file

@ -26,6 +26,7 @@ typedef enum {
OBJ_GOAL_SIGN = 0x09,
OBJ_EXPLOSION = 0x0a,
OBJ_MONITOR_IMAGE = 0x0b,
OBJ_SHIELD = 0x0c,
} ObjectType;
#define MASK_FLIP_FLIPX 0x1 // Flip on X axis

View file

@ -75,6 +75,7 @@ typedef struct {
uint8_t framecount;
uint8_t holding_jump;
uint16_t iframes;
uint8_t shield;
PlayerAction action;
@ -102,7 +103,6 @@ CharaAnim *player_get_animation_by_name(Player *player, const char *name);
void player_update(Player *player);
void player_draw(Player *player, VECTOR *screen_pos);
void player_set_hurt(Player *player, int32_t hazard_x);
void player_set_ring_loss(Player *player, int32_t hazard_x, uint8_t num_rings);
void player_do_damage(Player *player, int32_t hazard_x);
#endif

View file

@ -244,6 +244,9 @@
<file name="RINGLOSS.VAG"
type="data"
source="${PROJECT_SOURCE_DIR}/assets/sfx/RINGLOSS.VAG" />
<file name="SHIELD.VAG"
type="data"
source="${PROJECT_SOURCE_DIR}/assets/sfx/SHIELD.VAG" />
</dir>
<dir name="BGM">

View file

@ -275,7 +275,10 @@ begin_render_routine:
poly->tpage = getTPage(1, 0, 576, 0);
poly->clut = getClut(0, 481);
sort_prim(poly, state->id == OBJ_RING ? OTZ_LAYER_OBJECTS : OTZ_LAYER_PLAYER);
sort_prim(poly,
((state->id == OBJ_RING) || (state->id == OBJ_SHIELD))
? OTZ_LAYER_OBJECTS
: OTZ_LAYER_PLAYER);
if(!in_fragment && (typedata->fragment != NULL)) {
in_fragment = 1;

View file

@ -23,6 +23,7 @@ extern SoundEffect sfx_sprn;
extern SoundEffect sfx_chek;
extern SoundEffect sfx_death;
extern SoundEffect sfx_ringl;
extern SoundEffect sfx_shield;
extern int debug_mode;
extern uint8_t level_ring_count;
@ -44,6 +45,7 @@ static void _checkpoint_update(ObjectState *state, ObjectTableEntry *, VECTOR *p
static void _spikes_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos);
static void _explosion_update(ObjectState *state, ObjectTableEntry *, VECTOR *);
static void _monitor_image_update(ObjectState *state, ObjectTableEntry *, VECTOR *);
static void _shield_update(ObjectState *state, ObjectTableEntry *, VECTOR *);
// Player hitbox information. Calculated once per frame.
static int32_t player_vx, player_vy; // Top left corner of player hitbox
@ -104,6 +106,7 @@ object_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos)
case OBJ_SPIKES: _spikes_update(state, typedata, pos); break;
case OBJ_EXPLOSION: _explosion_update(state, typedata, pos); break;
case OBJ_MONITOR_IMAGE: _monitor_image_update(state, typedata, pos); break;
case OBJ_SHIELD: _shield_update(state, typedata, pos); break;
}
}
@ -473,14 +476,7 @@ _spikes_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
((player_vx >= solidity_vx - 8) && ((player_vx + 8) <= solidity_vx + 32)))
{
if(player.action != ACTION_HURT && player.iframes == 0) {
if(level_ring_count > 0) {
player_set_ring_loss(&player, (solidity_vx + 16) << 12, level_ring_count);
level_ring_count = 0;
sound_play_vag(sfx_ringl, 0);
} else {
player_set_hurt(&player, (solidity_vx + 16) << 12);
sound_play_vag(sfx_death, 0);
}
player_do_damage(&player, (solidity_vx + 16) << 12);
return;
}
@ -520,6 +516,7 @@ static void
_monitor_image_update(ObjectState *state, ObjectTableEntry *, VECTOR *)
{
state->timer++;
PoolObject *newobj;
// Monitor images ascend for 15 frames, then stay still for 15 more
if(state->timer <= 15) state->freepos->vy -= (ONE << 1);
@ -527,11 +524,39 @@ _monitor_image_update(ObjectState *state, ObjectTableEntry *, VECTOR *)
state->props |= OBJ_FLAG_DESTROYED;
switch(state->anim_state.animation) {
case MONITOR_KIND_NONE:
sound_play_vag(sfx_death, 0);
break;
case MONITOR_KIND_RING:
sound_play_vag(sfx_ring, 0);
level_ring_count += 10;
break;
case MONITOR_KIND_SHIELD:
player.shield = 1;
newobj = object_pool_create(OBJ_SHIELD);
newobj->freepos.vx = player.pos.vx;
newobj->freepos.vy = player.pos.vy + (20 << 12);
sound_play_vag(sfx_shield, 0);
break;
default: break;
}
}
}
static void
_shield_update(ObjectState *state, ObjectTableEntry *, VECTOR *)
{
// Just stay with the player and disappear if player gets hurt
if(!player.shield) {
state->props |= OBJ_FLAG_DESTROYED;
return;
}
state->freepos->vx = player.pos.vx;
state->freepos->vy = player.pos.vy + (20 << 12);
// Compensate position since it is drawn before player update
state->freepos->vx += player.vel.vx;
state->freepos->vy += player.vel.vy;
}

View file

@ -30,24 +30,26 @@
extern int debug_mode;
SoundEffect sfx_jump = { 0 };
SoundEffect sfx_skid = { 0 };
SoundEffect sfx_roll = { 0 };
SoundEffect sfx_dash = { 0 };
SoundEffect sfx_relea = { 0 };
SoundEffect sfx_dropd = { 0 };
SoundEffect sfx_ring = { 0 };
SoundEffect sfx_pop = { 0 };
SoundEffect sfx_sprn = { 0 };
SoundEffect sfx_chek = { 0 };
SoundEffect sfx_death = { 0 };
SoundEffect sfx_ringl = { 0 };
SoundEffect sfx_jump = { 0 };
SoundEffect sfx_skid = { 0 };
SoundEffect sfx_roll = { 0 };
SoundEffect sfx_dash = { 0 };
SoundEffect sfx_relea = { 0 };
SoundEffect sfx_dropd = { 0 };
SoundEffect sfx_ring = { 0 };
SoundEffect sfx_pop = { 0 };
SoundEffect sfx_sprn = { 0 };
SoundEffect sfx_chek = { 0 };
SoundEffect sfx_death = { 0 };
SoundEffect sfx_ringl = { 0 };
SoundEffect sfx_shield = { 0 };
// TODO: Maybe shouldn't be extern?
extern TileMap16 map16;
extern TileMap128 map128;
extern LevelData leveldata;
extern Camera camera;
extern uint8_t level_ring_count;
void
load_player(Player *player,
@ -64,6 +66,7 @@ load_player(Player *player,
player->airdirlock = 0;
player->framecount = 0;
player->iframes = 0;
player->shield = 0;
player_set_animation_direct(player, ANIM_STOPPED);
player->anim_frame = player->anim_timer = 0;
@ -80,18 +83,19 @@ load_player(Player *player,
player->action = ACTION_NONE;
if(sfx_jump.addr == 0) sfx_jump = sound_load_vag("\\SFX\\JUMP.VAG;1");
if(sfx_skid.addr == 0) sfx_skid = sound_load_vag("\\SFX\\SKIDDING.VAG;1");
if(sfx_roll.addr == 0) sfx_roll = sound_load_vag("\\SFX\\ROLL.VAG;1");
if(sfx_dash.addr == 0) sfx_dash = sound_load_vag("\\SFX\\DASH.VAG;1");
if(sfx_relea.addr == 0) sfx_relea = sound_load_vag("\\SFX\\RELEA.VAG;1");
if(sfx_dropd.addr == 0) sfx_dropd = sound_load_vag("\\SFX\\DROPD.VAG;1");
if(sfx_ring.addr == 0) sfx_ring = sound_load_vag("\\SFX\\RING.VAG;1");
if(sfx_pop.addr == 0) sfx_pop = sound_load_vag("\\SFX\\POP.VAG;1");
if(sfx_sprn.addr == 0) sfx_sprn = sound_load_vag("\\SFX\\SPRN.VAG;1");
if(sfx_chek.addr == 0) sfx_chek = sound_load_vag("\\SFX\\CHEK.VAG;1");
if(sfx_death.addr == 0) sfx_death = sound_load_vag("\\SFX\\DEATH.VAG;1");
if(sfx_ringl.addr == 0) sfx_ringl = sound_load_vag("\\SFX\\RINGLOSS.VAG;1");
if(sfx_jump.addr == 0) sfx_jump = sound_load_vag("\\SFX\\JUMP.VAG;1");
if(sfx_skid.addr == 0) sfx_skid = sound_load_vag("\\SFX\\SKIDDING.VAG;1");
if(sfx_roll.addr == 0) sfx_roll = sound_load_vag("\\SFX\\ROLL.VAG;1");
if(sfx_dash.addr == 0) sfx_dash = sound_load_vag("\\SFX\\DASH.VAG;1");
if(sfx_relea.addr == 0) sfx_relea = sound_load_vag("\\SFX\\RELEA.VAG;1");
if(sfx_dropd.addr == 0) sfx_dropd = sound_load_vag("\\SFX\\DROPD.VAG;1");
if(sfx_ring.addr == 0) sfx_ring = sound_load_vag("\\SFX\\RING.VAG;1");
if(sfx_pop.addr == 0) sfx_pop = sound_load_vag("\\SFX\\POP.VAG;1");
if(sfx_sprn.addr == 0) sfx_sprn = sound_load_vag("\\SFX\\SPRN.VAG;1");
if(sfx_chek.addr == 0) sfx_chek = sound_load_vag("\\SFX\\CHEK.VAG;1");
if(sfx_death.addr == 0) sfx_death = sound_load_vag("\\SFX\\DEATH.VAG;1");
if(sfx_ringl.addr == 0) sfx_ringl = sound_load_vag("\\SFX\\RINGLOSS.VAG;1");
if(sfx_shield.addr == 0) sfx_shield = sound_load_vag("\\SFX\\SHIELD.VAG;1");
}
void
@ -715,8 +719,28 @@ player_draw(Player *player, VECTOR *pos)
player->anim_dir < 0);
}
void _player_set_hurt(Player *player, int32_t hazard_x);
void _player_set_ring_loss(Player *player, int32_t hazard_x, uint8_t num_rings);
void
player_set_hurt(Player *player, int32_t hazard_x)
player_do_damage(Player *player, int32_t hazard_x)
{
// TODO: Missing death routine
if((player->shield > 0)
|| (level_ring_count == 0)) { // TODO: Remove this in favor of a death
player->shield = 0;
_player_set_hurt(player, hazard_x);
sound_play_vag(sfx_death, 0);
return;
}
_player_set_ring_loss(player, hazard_x, level_ring_count);
level_ring_count = 0;
sound_play_vag(sfx_ringl, 0);
}
void
_player_set_hurt(Player *player, int32_t hazard_x)
{
player->action = ACTION_HURT;
player->grnd = 0;
@ -733,9 +757,9 @@ player_set_hurt(Player *player, int32_t hazard_x)
#define RING_START_SPD_DIRECT 4
void
player_set_ring_loss(Player *player, int32_t hazard_x, uint8_t num_rings)
_player_set_ring_loss(Player *player, int32_t hazard_x, uint8_t num_rings)
{
player_set_hurt(player, hazard_x);
_player_set_hurt(player, hazard_x);
num_rings = num_rings > 32 ? 32 : num_rings;

View file

@ -42,6 +42,7 @@ class ObjectId(Enum):
# or effect.
EXPLOSION = 0x0a
MONITOR_IMAGE = 0x0b
SHIELD = 0x0c
@staticmethod
def get(name):
@ -58,6 +59,7 @@ class ObjectId(Enum):
"switch": ObjectId.SWITCH,
"explosion": ObjectId.EXPLOSION,
"monitor_image": ObjectId.MONITOR_IMAGE,
"shield": ObjectId.SHIELD,
}
result = switch.get(name.lower())
assert result is not None, f"Unknown common object {name}"