/* Kitsune's Curse Copyright (C) 2020-2023 Juan J. Martinez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "cpcrslib/cpcrslib.h" #include "splib.h" #include "plw.h" #include "sound.h" #include "main.h" #include "maps.h" #include "stage.h" // generated #include "player.h" #include "explo.h" #include "entities.h" #include "et_effect.h" #define LOCAL #include "et_player.h" void player_checkpoint() { #ifdef DEBUG char b[4]; #endif // don't do it if not solid or platform if (is_map_blocked(px + 3, py + 24) == 1) { smap = cmap; spx = px; spy = py; sdir = dir; #ifdef DEBUG set_text_ink(15, 15, 15); put_text("C", 10, 192); pad_numbers(b, 3, px); put_text(b, 13, 192); pad_numbers(b, 3, py); put_text(b, 20, 192); #endif } } void player_hit(uint8_t h) { life = life > h ? life - h : 0; if (!life) { // dead // instant death cases control the frame // otherwise set it here if (h != MAX_LIFE) frame = WALK + 1; erase_sprite(px, py, 3); was_hit = 0; respawn_delay = RESPAWN_DELAY; // not water if (last_deadly != DEADLY_TILE_BASE) PLW_PlaySoundEffectP(EFX_DEATH); if (lives == 1) PLW_Init(songs, SONG_SILENCE); } else { // only hit was_hit = WAS_HIT; if (*it_x > px) dir = DIR_RIGHT; else dir = DIR_LEFT; PLW_PlaySoundEffectP(EFX_DAMAGE); } draw_hud(); } void draw_player() { if ((!was_hit || was_hit & 2) && !magic && life) put_sprite4(player[player_frames[frame]], px, py, 3, dir); else if (magic) put_sprite4(explo[2], px, py + 6, 2, magic & 1); if (!life && frame && respawn_delay > 2 && respawn_delay & 2) put_sprite4(player[player_frames[frame]], px, py, 3, dir); erase_sprite(opx, opy, 3); opx = px; opy = py; } void update_player() { // help is_map_blocked sp_it = NULL; moved = 0; if (respawn_delay) { if (--respawn_delay) return; --lives; life = lives ? MAX_LIFE : 0; draw_hud(); if (!lives) { gameover_delay = GAMEOVER_DELAY; return; } if (cmap != smap) init_map(smap); px = spx; py = spy; dir = sdir; frame = WALK; player_h = 0; was_hit = RESPAWN_DELAY; return; } if (!lives) return; if (was_hit) { --was_hit; // jump after being hit if (was_hit == WAS_HIT - 1) { jump_flag = 1; player_h = 2; } // jump back after being hit if (was_hit > RESPAWN_DELAY) { moved = 1; frame = WALK + 1; if (dir) { if (px < TW * TMW - 8 && !is_map_blocked(px + 8, py + 23) && !is_map_blocked(px + 8, py + (player_h ? 6 : 0))) px += 2; if (px == TW * TMW - 8 && exit_map_right()) return; } else { if (px > 0 && !is_map_blocked(px - 1, py + 23) && !is_map_blocked(px - 1, py + (player_h ? 6 : 0))) px -= 2; if (!px && exit_map_left()) return; } } } // check for gravity if (!player_h && !is_map_blocked(px + 1, py + 24) && !is_map_blocked(px + 6, py + 24)) { // start falling player_h = JUMP_SEQ - 2; frame = JUMP; moved = 1; } if (cpc_TestKeyF(KEY_DOWN) && frame != JUMP) { if (frame != CROUCH) frame = CROUCH; } else { // wake up if (frame == CROUCH) frame = WALK; } if (cpc_TestKeyF(KEY_UP)) { if (!player_h && !jump_flag // no magic or magic just started && (!magic || magic > COOL_DOWN - 2)) { jump_flag = 1; player_h = 1; frame = JUMP; } } else { // faster than always set to 0 if (jump_flag) jump_flag = 0; } if (cpc_TestKeyF(KEY_RIGHT) && !cpc_TestKeyF(KEY_LEFT)) { if (dir) dir = DIR_RIGHT; if (frame != CROUCH) { moved = 1; if (px < TW * TMW - 8 && !is_map_blocked(px + 8, py + 23) && !is_map_blocked(px + 8, py + (player_h ? 6 : 0))) px += 2; if (magic && px < TW * TMW - 8 && !is_map_blocked(px + 8, py + 23) && !is_map_blocked(px + 8, py + (player_h ? 6 : 0))) px += 2; if (px == TW * TMW - 8 && exit_map_right()) return; } } if (cpc_TestKeyF(KEY_LEFT) && !cpc_TestKeyF(KEY_RIGHT)) { if (!dir) dir = DIR_LEFT; if (frame != CROUCH) { moved = 1; if (px > 0 && !is_map_blocked(px - 1, py + 23) && !is_map_blocked(px - 1, py + (player_h ? 6 : 0))) px -= 2; if (magic && px > 0 && !is_map_blocked(px - 1, py + 23) && !is_map_blocked(px - 1, py + (player_h ? 6 : 0))) px -= 2; if (!px && exit_map_left()) return; } } if (magic) { if (magic-- == 2) new_explo(); if (!magic && (is_map_deadly(px + 3, py + 24) || is_map_deadly(px + 3, py + (frame == CROUCH ? 6 : 0)) )) { if (last_deadly == DEADLY_TILE_BASE) { frame = 0; new_splash(); } else frame = WALK + 1; player_hit(MAX_LIFE); return; } } else { if (cool_down) --cool_down; if (cpc_TestKeyF(KEY_FIRE) && !cool_down) { magic = COOL_DOWN; cool_down = COOL_DOWN + 2; new_explo(); } } if (player_h) { // jumping it_k = jump_seq[player_h - 1]; if (IS_GOING_DOWN(player_h)) { // down while (it_k && py < TH * TMH - 24) { // potentially hit floor if ((is_map_blocked(px + 1, py + 24) || is_map_blocked(px + 6, py + 24))) { // process deadly first if (is_map_deadly(px + 1, py + 24) || is_map_deadly(px + 6, py + 24)) { if (!magic) { if (last_deadly == DEADLY_TILE_BASE) { frame = 0; new_splash(); } else frame = WALK + 1; player_hit(MAX_LIFE); } break; } // avoid getting *inside* the platform if (!is_map_blocked(px + 1, py + 22) && !is_map_blocked(px + 6, py + 22)) { // hit floor player_h = 0; frame = WALK; player_checkpoint(); if (!magic) PLW_PlaySoundEffectP(EFX_HIT); break; } } py += 2; it_k -= 2; } if (py == TH * TMH - 24 && exit_map_down()) return; } else { // up while (it_k && py) { // jumping back after being hit if (was_hit > RESPAWN_DELAY) { if (is_map_blocked(px + 1, py) || is_map_blocked(px + 6, py)) break; } if (is_map_blocked(px + 1, py + 4) || is_map_blocked(px + 6, py + 4)) { if (!magic) { if (is_map_deadly(px + 3, py + 4)) { frame = WALK + 1; player_hit(MAX_LIFE); } else if (jump_flag == 1) { jump_flag = 2; PLW_PlaySoundEffectP(EFX_HIT); } } break; } py -= 2; it_k -= 2; } if (py == 0 && exit_map_up()) return; } if (player_h && player_h < JUMP_SEQ // extra boost with magic but not first step && (!(magic & 1) || player_h == 1)) player_h++; } else { // not jumping if (moved) { if (!magic && (is_map_deadly(px + 3, py + 24) || is_map_deadly(px + 3, py))) { if (last_deadly == DEADLY_TILE_BASE) { frame = 0; new_splash(); } else frame = WALK + 1; player_hit(MAX_LIFE); return; } if (wdelay++) { wdelay = 0; // frame increase if (frame != JUMP && ++frame > WALK_CYCLE) frame = WALK; } } else { // frame stopped if (frame > WALK && frame < CROUCH) { frame = WALK; wdelay = 0; } } } } #pragma save #pragma disable_warning 85 #pragma disable_warning 59 uint8_t check_for_player(uint8_t h) __z88dk_fastcall { /* if (magic || was_hit || !life) return 0; if (frame == CROUCH) { if (py + 8 < sp_it->y + h && sp_it->y < py + 24 && px + 2 < sp_it->x + w && sp_it->x < px + 6) return 1; } else { if (py < sp_it->y + h && sp_it->y < py + 24 && px + 2 < sp_it->x + w && sp_it->x < px + 6) return 1; } return 0; */ // *INDENT-OFF* __asm; ld e, #8 ; w ld d, l ; h ld a, (_magic) or a jr nz, check_for_player_false ld a, (_was_hit) or a jr nz, check_for_player_false ld a, (_life) or a jr z, check_for_player_false ld hl, (_sp_it) ld bc, #6 add hl, bc ld a, (hl) ; y add d ld c, a ; b is 0 ld a, (_frame) cp #CROUCH jr nz, not_crouching ld b, #8 not_crouching: ld a, (_py) add a, b cp c jr nc, check_for_player_false ld a, (_py) add #24 ld c, a ld a, (hl) ; y cp c jr nc, check_for_player_false dec hl dec hl ld a, (hl) ; x add e ld c, a ld a, (_px) add #2 cp c jr nc, check_for_player_false ld a, (_px) add #6 ld c, a ld a, (hl) ; x cp c jr nc, check_for_player_false ld l, #1 ret check_for_player_false: ld l, #0 __endasm; // *INDENT-ON* } #pragma restore