diff --git a/draw.c b/draw.c index c31e2f7..4d25e3e 100644 --- a/draw.c +++ b/draw.c @@ -40,7 +40,9 @@ void Draw_Player( SDL_Renderer* r ) { } // jump tile else if ( gs->ps.do_jump || !gs->ps.on_ground ) - til = gs->ps.last_dir >= 0 ? 67 : 68; + til = gs->ps.last_dir >= 0 ? 67 : 68; + // dead + if ( gs->ps.dead_timer ) til = 129; // render // grounded debug @@ -75,10 +77,10 @@ void Draw_Monsters( SDL_Renderer* r ) { for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { monster_state_t* m = &gs->ms[i]; if ( m->type ) { - dst.x = m->px - gs->view_x * TILE_SIZE - 12; - dst.y = TILE_SIZE + m->py - 10; + dst.x = m->px - gs->view_x * TILE_SIZE;// - 12; + dst.y = TILE_SIZE + m->py;// - 10; dst.w = 24; dst.h = 20; - til = m->type; + til = m->dead_timer ? 129 : m->type; SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst ); } } diff --git a/game.c b/game.c index d658b25..4d853c3 100644 --- a/game.c +++ b/game.c @@ -14,6 +14,8 @@ static void G_Init() { // clean player state memset( &gs->ps, 0, sizeof(player_state_t) ); + // 3 lives per game + gs->ps.lives = 255; // clean monster states memset( gs->ms, 0, sizeof(gs->ms) ); } diff --git a/monster.c b/monster.c index c8b33c9..365bae8 100644 --- a/monster.c +++ b/monster.c @@ -6,7 +6,7 @@ extern game_state_t* gs; void M_Move() { for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { monster_state_t* m = &gs->ms[i]; - if ( m->type ) { + if ( m->type && !m->dead_timer ) { if ( !m->npx && !m->npy ) { m->npx = gs->levels[gs->current_level].path[m->path_index]; m->npy = gs->levels[gs->current_level].path[m->path_index + 1]; @@ -34,13 +34,14 @@ void M_Fire() { if ( !gs->mbullet_px && !gs->mbullet_py ) { for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { monster_state_t* m = &gs->ms[i]; - if ( m->type && W_IsVisible( m->px ) && W_IsClear( m->px, m->py, 0 ) ) { + // assumed size of 24x20 + if ( m->type && !m->dead_timer && W_IsVisible( m->px ) && W_IsClear( m->px+12, m->py+10, 0 ) ) { gs->mbullet_dir = gs->ps.px < m->px ? -1 : 1; if ( gs->mbullet_dir == 1 ) - gs->mbullet_px = m->px; + gs->mbullet_px = m->px + 18; if ( gs->mbullet_dir == -1 ) - gs->mbullet_px = m->px - 20; - gs->mbullet_py = m->py;// + 8; + gs->mbullet_px = m->px - 10; + gs->mbullet_py = m->py + 10; } } } @@ -50,7 +51,14 @@ void M_UpdateBullet() { if ( !gs->mbullet_px || !gs->mbullet_py ) return; if ( !W_IsClear( gs->mbullet_px, gs->mbullet_py, 0 ) || !W_IsVisible( gs->mbullet_px ) ) gs->mbullet_px = gs->mbullet_py = 0; - if ( gs->mbullet_px ) + if ( gs->mbullet_px ) { gs->mbullet_px += gs->mbullet_dir * 4; + uint8_t tx = gs->mbullet_px / TILE_SIZE; + uint8_t ty = gs->mbullet_py / TILE_SIZE; + if ( tx == gs->ps.tx && ty == gs->ps.ty && !gs->ps.dead_timer ) { + gs->mbullet_px = gs->mbullet_py = 0; + gs->ps.dead_timer = 30; + } + } } diff --git a/monster.h b/monster.h index 0ae73cf..e477943 100644 --- a/monster.h +++ b/monster.h @@ -4,6 +4,7 @@ typedef struct { uint8_t type; // type and tile index + uint8_t dead_timer; uint8_t path_index; // current point in path uint8_t tx, ty; // tile pos int16_t px, py; // pixel pos diff --git a/player.c b/player.c index 42d4f9e..4530680 100644 --- a/player.c +++ b/player.c @@ -26,6 +26,7 @@ void P_Spawn() { gs->ps.do_fire = 0; gs->ps.do_jetpack = 0; gs->ps.do_up = 0; gs->ps.do_down = 0; + gs->ps.dead_timer = 0; // hardcoded player starts switch ( gs->current_level ) { @@ -69,6 +70,7 @@ void P_PickupItem() { // update collision point clear flags void P_UpdateCollision() { + if ( gs->ps.dead_timer ) return; // 8 points of collision; relative to top left of tile 56 neutral frame (20x16) // 0, 1 = top left, top right gs->ps.col_point[0] = W_IsClear( gs->ps.px + 4, gs->ps.py - 0, 1 ); @@ -91,20 +93,35 @@ void P_UpdateBullet() { // skip if no bullet in world if ( !gs->ps.bullet_px || !gs->ps.bullet_py ) return; - gs->ps.bullet_px += gs->ps.bullet_dir * 4; - // collision if ( !W_IsClear( gs->ps.bullet_px, gs->ps.bullet_py, 0 ) ) gs->ps.bullet_px = gs->ps.bullet_py = 0; // off-screen uint8_t tx = gs->ps.bullet_px / TILE_SIZE; + uint8_t ty = gs->ps.bullet_py / TILE_SIZE; if ( tx - gs->view_x < 0 || tx - gs->view_x > 20 ) gs->ps.bullet_px = gs->ps.bullet_py = 0; + + if ( gs->ps.bullet_px ) { + gs->ps.bullet_px += gs->ps.bullet_dir * 4; + + for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { + monster_state_t* m = &gs->ms[i]; + if ( m->type && !m->dead_timer ) { + if ( (ty == m->ty || ty == m->ty + 1) && (tx == m->tx || tx == m->tx + 1) ) { + gs->ps.bullet_px = gs->ps.bullet_py = 0; + m->dead_timer = 30; + } + } + } + } } // validate input whose try flags were set void P_VerifyInput() { + // no input when dead + if ( gs->ps.dead_timer ) return; // right; col points 2, 3 if ( gs->ps.try_right && gs->ps.col_point[2] && gs->ps.col_point[3] ) { gs->ps.do_right = 1; @@ -145,6 +162,7 @@ void P_VerifyInput() { // apply validated player movement void P_Move() { + if ( gs->ps.dead_timer ) return; // update player's tile pos // sample x towards the center gs->ps.tx = (gs->ps.px + TILE_SIZE / 2) / TILE_SIZE; @@ -208,6 +226,7 @@ void P_Move() { // apply gravity to player void P_ApplyGravity() { + if ( gs->ps.dead_timer ) return; if ( !gs->ps.do_jump && !gs->ps.on_ground && !gs->ps.do_jetpack ) { // check below sprite if ( W_IsClear( gs->ps.px + 4, gs->ps.py + 17, 0 ) && W_IsClear( gs->ps.px + 10, gs->ps.py + 17, 0 ) ) @@ -221,3 +240,4 @@ void P_ApplyGravity() { } } } + diff --git a/player.h b/player.h index 26abae6..6095972 100644 --- a/player.h +++ b/player.h @@ -29,6 +29,7 @@ typedef struct { uint8_t do_up, do_down; uint8_t jump_timer; + uint8_t dead_timer; // pickup tile pos uint8_t check_pickup_x; uint8_t check_pickup_y; diff --git a/world.c b/world.c index 3672cd8..c4397d2 100644 --- a/world.c +++ b/world.c @@ -23,6 +23,11 @@ void W_StartLevel() { gs->ms[1].px = 59 * TILE_SIZE; gs->ms[1].py = 4 * TILE_SIZE; } break; + case 3: { // level 4, one monster + gs->ms[0].type = 93; + gs->ms[0].px = 32 * TILE_SIZE; + gs->ms[0].py = 2 * TILE_SIZE; + } break; } // reset items @@ -35,6 +40,7 @@ void W_StartLevel() { // hard reset current level from original data void W_ResetLevel() { Util_GetLevel( gs->current_level, &gs->levels[gs->current_level] ); + gs->ps.lives = 255; W_StartLevel(); } @@ -58,7 +64,7 @@ uint8_t W_IsClear( int16_t px, int16_t py, uint8_t is_player ) { if ( til >= 29 && til <= 30 ) return 0; // player collision functionality - if ( is_player ) { + if ( is_player && !gs->ps.dead_timer ) { // adjusted tile collision SDL_Rect colbox; colbox.x = (tx - gs->view_x) * TILE_SIZE + 2; @@ -71,7 +77,8 @@ uint8_t W_IsClear( int16_t px, int16_t py, uint8_t is_player ) { if ( til == 6 || til == 25 || til == 36 ) { if ( SDL_PointInRect( &colpt, &colbox ) ) { //return 0; - P_Spawn(); + //P_Spawn(); + gs->ps.dead_timer = 30; } } @@ -116,6 +123,31 @@ void W_Update() { gs->ps.check_door = 0; } } + // update dead timers + if ( gs->ps.dead_timer ) { + gs->ps.dead_timer--; + if ( !gs->ps.dead_timer ) { + if ( gs->ps.lives ) { + gs->ps.lives--; + P_Spawn(); + } else gs->quit = 1; + } + } + // monsters + for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { + monster_state_t* m = &gs->ms[i]; + if ( m->type ) { + if ( m->dead_timer ) { + m->dead_timer--; + if ( !m->dead_timer ) { m->type = 0; } + } else { // player and monster collision + if ( m->tx == gs->ps.tx && m->ty == gs->ps.ty ) { + m->dead_timer = 30; + gs->ps.dead_timer = 30; + } + } + } + } } // update game view based on set scroll values