aboutsummaryrefslogtreecommitdiff
path: root/src/et_player.c
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-11-05 11:22:55 +0000
committerJuan J. Martinez <jjm@usebox.net>2023-11-05 11:31:28 +0000
commit2fbdf974338bde8576efdae40a819a76b2391033 (patch)
tree64d41a37470143f142344f9a439d96de3e7918c2 /src/et_player.c
downloadkitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.tar.gz
kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.zip
Initial import of the open source release
Diffstat (limited to 'src/et_player.c')
-rw-r--r--src/et_player.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/src/et_player.c b/src/et_player.c
new file mode 100644
index 0000000..d58d656
--- /dev/null
+++ b/src/et_player.c
@@ -0,0 +1,551 @@
+/*
+ Kitsune's Curse
+ Copyright (C) 2020-2023 Juan J. Martinez <jjm@usebox.net>
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+
+#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