From 3c7283f1c7258d94ed3f3d4716998a8812c36deb Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Mon, 3 Oct 2022 20:36:21 +0200 Subject: [PATCH] player: refactor power handling Separate concepts of "stored" and "effective" power. --- src/item.c | 2 +- src/player.c | 57 ++++++++++++++++++++++++++--------------- src/player.h | 12 +++++---- src/plrmodes/marisa_a.c | 6 ++--- src/plrmodes/marisa_b.c | 6 ++--- src/plrmodes/reimu_a.c | 10 ++++---- src/plrmodes/reimu_b.c | 6 ++--- src/plrmodes/youmu_a.c | 4 +-- src/plrmodes/youmu_b.c | 6 ++--- src/replay/stage.c | 5 ++-- src/stage.c | 8 ++---- src/stagedraw.c | 8 +++--- 12 files changed, 72 insertions(+), 58 deletions(-) diff --git a/src/item.c b/src/item.c index 76b5957c..8ec235f5 100644 --- a/src/item.c +++ b/src/item.c @@ -248,7 +248,7 @@ void process_items(void) { bool may_collect = true; if( - (item->type == ITEM_POWER_MINI && global.plr.power == PLR_MAX_POWER) || + (item->type == ITEM_POWER_MINI && global.plr.power_stored >= PLR_MAX_POWER_EFFECTIVE) || (item->type == ITEM_SURGE && !player_is_powersurge_active(&global.plr)) ) { item->type = ITEM_PIV; diff --git a/src/player.c b/src/player.c index 9e04d6d4..ac5a05a6 100644 --- a/src/player.c +++ b/src/player.c @@ -39,7 +39,7 @@ void player_init(Player *plr) { plr->lives = PLR_START_LIVES; plr->bombs = PLR_START_BOMBS; plr->point_item_value = PLR_START_PIV; - plr->power = 100; + plr->power_stored = 100; plr->deathtime = -1; plr->continuetime = -1; plr->bomb_triggertime = -1; @@ -112,35 +112,48 @@ static void player_full_power(Player *plr) { stagetext_add("Full Power!", VIEWPORT_W * 0.5 + VIEWPORT_H * 0.33 * I, ALIGN_CENTER, res_font("big"), RGB(1, 1, 1), 0, 60, 20, 20); } +static int player_track_effective_power_change(Player *plr) { + int old_effective = plr->_prev_effective_power; + int new_effective = player_get_effective_power(plr); + + if(old_effective != new_effective) { + coevent_signal(&plr->events.effective_power_changed); + } + + plr->_prev_effective_power = old_effective; + return new_effective; +} + bool player_set_power(Player *plr, short npow) { - int pow_base = clamp(npow, 0, PLR_MAX_POWER); - int pow_overflow = clamp(npow - PLR_MAX_POWER, 0, PLR_MAX_POWER_OVERFLOW); + int old_stored = plr->power_stored; + int new_stored = iclamp(npow, 0, PLR_MAX_POWER_STORED); + plr->power_stored = new_stored; - int oldpow = plr->power; - int oldpow_over = plr->power_overflow; - - plr->power = pow_base; - plr->power_overflow = pow_overflow; - - if((oldpow + oldpow_over) / 100 < (pow_base + pow_overflow) / 100) { + if(old_stored / 100 < new_stored / 100) { play_sfx("powerup"); } - if(plr->power == PLR_MAX_POWER && oldpow < PLR_MAX_POWER) { - player_full_power(plr); - } - - bool change = (oldpow + oldpow_over) != (plr->power + plr->power_overflow); + bool change = old_stored != new_stored; if(change) { - coevent_signal(&plr->events.power_changed); + if(new_stored >= PLR_MAX_POWER_EFFECTIVE && old_stored < PLR_MAX_POWER_EFFECTIVE) { + player_full_power(plr); + } + + coevent_signal(&plr->events.stored_power_changed); } + player_track_effective_power_change(plr); + return change; } bool player_add_power(Player *plr, short pdelta) { - return player_set_power(plr, plr->power + plr->power_overflow + pdelta); + return player_set_power(plr, plr->power_stored + pdelta); +} + +int player_get_effective_power(Player *plr) { + return iclamp(plr->power_stored, 0, PLR_MAX_POWER_EFFECTIVE); } void player_move(Player *plr, cmplx delta) { @@ -554,6 +567,8 @@ DEFINE_TASK(player_logic) { Player *plr = TASK_BIND(ARGS.plr); uint prev_inputflags = 0; + plr->_prev_effective_power = player_get_effective_power(plr); + for(;;) { YIELD; @@ -580,7 +595,7 @@ DEFINE_TASK(player_logic) { stats_track_continue_used(&plr->stats); player_set_power(plr, 0); stage_clear_hazards(CLEAR_HAZARDS_ALL); - spawn_items(plr->deathpos, ITEM_POWER, (int)ceil(PLR_MAX_POWER/(double)POWER_VALUE)); + spawn_items(plr->deathpos, ITEM_POWER, (int)ceil(PLR_MAX_POWER_EFFECTIVE/(real)POWER_VALUE)); } aniplayer_update(&plr->ani); @@ -612,6 +627,8 @@ DEFINE_TASK(player_logic) { } else if(plr->deathtime > global.frames) { stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW); } + + player_track_effective_power_change(plr); } } @@ -677,7 +694,7 @@ static bool player_powersurge(Player *plr) { !player_is_alive(plr) || player_is_bomb_active(plr) || player_is_powersurge_active(plr) || - plr->power + plr->power_overflow < PLR_POWERSURGE_POWERCOST + plr->power_stored < PLR_POWERSURGE_POWERCOST ) { return false; } @@ -856,7 +873,7 @@ void player_realdeath(Player *plr) { return; } - int total_power = plr->power + plr->power_overflow; + int total_power = plr->power_stored; int drop = fmax(2, (total_power * 0.15) / POWER_VALUE); spawn_items(plr->deathpos, ITEM_POWER, drop); diff --git a/src/player.h b/src/player.h index 37f73941..c3ed8546 100644 --- a/src/player.h +++ b/src/player.h @@ -30,8 +30,8 @@ #include "replay/eventcodes.h" enum { - PLR_MAX_POWER = 400, - PLR_MAX_POWER_OVERFLOW = 200, + PLR_MAX_POWER_EFFECTIVE = 400, + PLR_MAX_POWER_STORED = 600, PLR_MAX_LIVES = 8, PLR_MAX_BOMBS = 8, @@ -121,7 +121,8 @@ DEFINE_ENTITY_TYPE(Player, { COEVENTS_ARRAY( shoot, inputflags_changed, - power_changed, + stored_power_changed, + effective_power_changed, bomb_used ) events; @@ -137,8 +138,8 @@ DEFINE_ENTITY_TYPE(Player, { int bombs; int life_fragments; int bomb_fragments; - int power; - int power_overflow; + int power_stored; + int _prev_effective_power; int continuetime; int deathtime; /* time of hit + deathbomb window */ @@ -191,6 +192,7 @@ bool player_should_shoot(Player *plr); bool player_set_power(Player *plr, short npow); bool player_add_power(Player *plr, short pdelta); +int player_get_effective_power(Player *plr); void player_move(Player*, cmplx delta); diff --git a/src/plrmodes/marisa_a.c b/src/plrmodes/marisa_a.c index 732facad..72221010 100644 --- a/src/plrmodes/marisa_a.c +++ b/src/plrmodes/marisa_a.c @@ -664,13 +664,13 @@ static void marisa_laser_respawn_slaves(MarisaAController *ctrl, int power_rank) TASK(marisa_laser_power_handler, { MarisaAController *ctrl; }) { MarisaAController *ctrl = ARGS.ctrl; Player *plr = ctrl->plr; - int old_power = plr->power / 100; + int old_power = player_get_effective_power(plr) / 100; marisa_laser_respawn_slaves(ctrl, old_power); for(;;) { - WAIT_EVENT_OR_DIE(&plr->events.power_changed); - int new_power = plr->power / 100; + WAIT_EVENT_OR_DIE(&plr->events.effective_power_changed); + int new_power = player_get_effective_power(plr) / 100; if(old_power != new_power) { marisa_laser_respawn_slaves(ctrl, new_power); old_power = new_power; diff --git a/src/plrmodes/marisa_b.c b/src/plrmodes/marisa_b.c index 9d859d87..719a5945 100644 --- a/src/plrmodes/marisa_b.c +++ b/src/plrmodes/marisa_b.c @@ -270,13 +270,13 @@ static void marisa_star_respawn_slaves(MarisaBController *ctrl, int numslaves) { TASK(marisa_star_power_handler, { MarisaBController *ctrl; }) { MarisaBController *ctrl = ARGS.ctrl; Player *plr = ctrl->plr; - int old_power = plr->power / 100; + int old_power = player_get_effective_power(plr) / 100; marisa_star_respawn_slaves(ctrl, old_power); for(;;) { - WAIT_EVENT_OR_DIE(&plr->events.power_changed); - int new_power = plr->power / 100; + WAIT_EVENT_OR_DIE(&plr->events.effective_power_changed); + int new_power = player_get_effective_power(plr) / 100; if(old_power != new_power) { marisa_star_respawn_slaves(ctrl, new_power); old_power = new_power; diff --git a/src/plrmodes/reimu_a.c b/src/plrmodes/reimu_a.c index dde6d5bb..f08dabca 100644 --- a/src/plrmodes/reimu_a.c +++ b/src/plrmodes/reimu_a.c @@ -740,7 +740,7 @@ static void reimu_spirit_kill_slaves(ReimuAController *ctrl) { static void reimu_spirit_respawn_slaves(ReimuAController *ctrl) { Player *plr = ctrl->plr; - int power_rank = plr->power / 100; + int power_rank = player_get_effective_power(plr) / 100; reimu_spirit_kill_slaves(ctrl); @@ -779,11 +779,11 @@ TASK(reimu_spirit_focus_handler, { ReimuAController *ctrl; }) { TASK(reimu_spirit_power_handler, { ReimuAController *ctrl; }) { ReimuAController *ctrl = ARGS.ctrl; Player *plr = ctrl->plr; - int old_power = plr->power / 100; + int old_power = player_get_effective_power(plr) / 100; for(;;) { - WAIT_EVENT_OR_DIE(&plr->events.power_changed); - int new_power = plr->power / 100; + WAIT_EVENT_OR_DIE(&plr->events.effective_power_changed); + int new_power = player_get_effective_power(plr) / 100; if(old_power != new_power) { reimu_spirit_respawn_slaves(ctrl); old_power = new_power; @@ -832,7 +832,7 @@ TASK(reimu_spirit_shot_volley, { ReimuAController *ctrl; }) { for(;;) { WAIT_EVENT_OR_DIE(&plr->events.shoot); - int power_rank = plr->power / 100; + int power_rank = player_get_effective_power(plr) / 100; real damage = SHOT_VOLLEY_DMG; for(int pwr = 0; pwr <= power_rank; ++pwr) { diff --git a/src/plrmodes/reimu_b.c b/src/plrmodes/reimu_b.c index 9985b394..72640c60 100644 --- a/src/plrmodes/reimu_b.c +++ b/src/plrmodes/reimu_b.c @@ -606,13 +606,13 @@ TASK(reimu_dream_shot_forward, { ReimuBController *ctrl; }) { TASK(reimu_dream_power_handler, { ReimuBController *ctrl; }) { ReimuBController *ctrl = ARGS.ctrl; Player *plr = ctrl->plr; - int old_power = plr->power / 100; + int old_power = player_get_effective_power(plr) / 100; reimu_dream_respawn_slaves(ctrl, old_power * 2); for(;;) { - WAIT_EVENT_OR_DIE(&plr->events.power_changed); - int new_power = plr->power / 100; + WAIT_EVENT_OR_DIE(&plr->events.effective_power_changed); + int new_power = player_get_effective_power(plr) / 100; if(old_power != new_power) { reimu_dream_respawn_slaves(ctrl, new_power * 2); old_power = new_power; diff --git a/src/plrmodes/youmu_a.c b/src/plrmodes/youmu_a.c index e123ca04..f657d753 100644 --- a/src/plrmodes/youmu_a.c +++ b/src/plrmodes/youmu_a.c @@ -240,7 +240,7 @@ TASK(youmu_mirror_myon_shot, { YoumuAController *ctrl; }) { const real dmg_center = SHOT_MYON_DAMAGE; const real dmg_side = SHOT_MYON_DAMAGE; const real speed = -10; - const int power_rank = plr->power / 100; + const int power_rank = player_get_effective_power(plr) / 100; real spread; cmplx forward; @@ -567,7 +567,7 @@ TASK(youmu_mirror_shot_forward, { YoumuAController *ctrl; }) { play_sfx_loop("generic_shot"); cmplx v = -20 * I; - int power_rank = plr->power / 100; + int power_rank = player_get_effective_power(plr) / 100; real spread = M_PI/64 * (1 + 0.5 * psin(t/15.0)); diff --git a/src/plrmodes/youmu_b.c b/src/plrmodes/youmu_b.c index 128c422e..66121768 100644 --- a/src/plrmodes/youmu_b.c +++ b/src/plrmodes/youmu_b.c @@ -176,7 +176,7 @@ TASK(youmu_haunting_shot_spread, { YoumuBController *ctrl; }) { continue; } - INVOKE_TASK(youmu_burst_shot, ctrl, 2 * plr->power / 100); + INVOKE_TASK(youmu_burst_shot, ctrl, 2 * player_get_effective_power(plr) / 100); WAIT(SHOT_SPREAD_DELAY); } } @@ -452,12 +452,12 @@ TASK(youmu_haunting_shot_orbs, { YoumuBController *ctrl; }) { continue; } - int power_rank = plr->power / 100; + int power_rank = player_get_effective_power(plr) / 100; INVOKE_TASK(youmu_orb_shot, .ctrl = ctrl, .lifetime = SHOT_ORBS_LIFETIME_BASE + power_rank * SHOT_ORBS_LIFETIME_PER_POWER, - .spirit_damage = SHOT_ORBS_SPIRIT_DAMAGE, // 120 - 18 * 4 * (1 - pow(1 - (plr->power / 100) / 4.0, 1.5)); + .spirit_damage = SHOT_ORBS_SPIRIT_DAMAGE, .spirit_spawn_delay = SHOT_ORBS_SPIRIT_SPAWN_DELAY ); diff --git a/src/replay/stage.c b/src/replay/stage.c index 4668b512..f79226d6 100644 --- a/src/replay/stage.c +++ b/src/replay/stage.c @@ -37,7 +37,7 @@ ReplayStage *replay_stage_new(Replay *rpy, StageInfo *stage, uint64_t start_time s->plr_life_fragments = plr->life_fragments; s->plr_bombs = plr->bombs; s->plr_bomb_fragments = plr->bomb_fragments; - s->plr_power = plr->power + plr->power_overflow; + s->plr_power = plr->power_stored; s->plr_graze = plr->graze; s->plr_point_item_value = plr->point_item_value; s->plr_inputflags = plr->inputflags; @@ -56,8 +56,7 @@ void replay_stage_sync_player_state(ReplayStage *stg, Player *plr) { plr->life_fragments = stg->plr_life_fragments; plr->bombs = stg->plr_bombs; plr->bomb_fragments = stg->plr_bomb_fragments; - plr->power = (stg->plr_power > PLR_MAX_POWER ? PLR_MAX_POWER : stg->plr_power); - plr->power_overflow = (stg->plr_power > PLR_MAX_POWER ? stg->plr_power - PLR_MAX_POWER : 0); + plr->power_stored = stg->plr_power; plr->graze = stg->plr_graze; plr->point_item_value = stg->plr_point_item_value; plr->inputflags = stg->plr_inputflags; diff --git a/src/stage.c b/src/stage.c index 4a11bcd5..85ef9a50 100644 --- a/src/stage.c +++ b/src/stage.c @@ -148,14 +148,10 @@ static void stage_start(StageInfo *stage) { } if(global.is_practice_mode) { - global.plr.power = config_get_int(CONFIG_PRACTICE_POWER); + global.plr.power_stored = config_get_int(CONFIG_PRACTICE_POWER); } - if(global.plr.power < 0) { - global.plr.power = 0; - } else if(global.plr.power > PLR_MAX_POWER) { - global.plr.power = PLR_MAX_POWER; - } + global.plr.power_stored = iclamp(global.plr.power_stored, 0, PLR_MAX_POWER_STORED); reset_all_sfx(); } diff --git a/src/stagedraw.c b/src/stagedraw.c index 72251888..00bdb758 100644 --- a/src/stagedraw.c +++ b/src/stagedraw.c @@ -1100,15 +1100,15 @@ static inline void stage_draw_hud_power_value(float xpos, float ypos) { Font *fnt_int = res_font("standard"); Font *fnt_fract = res_font("small"); - int pw = global.plr.power + global.plr.power_overflow; + int pw = global.plr.power_stored; Color *c_whole, c_whole_buf, *c_fract, c_fract_buf; Color *c_op_mod = RGBA(1, 0.2 + 0.3 * psin(global.frames / 10.0), 0.2, 1.0); - if(pw <= PLR_MAX_POWER) { + if(pw <= PLR_MAX_POWER_EFFECTIVE) { c_whole = &stagedraw.hud_text.color.active; c_fract = &stagedraw.hud_text.color.inactive; - } else if(pw - PLR_MAX_POWER < 100) { + } else if(pw - PLR_MAX_POWER_EFFECTIVE < 100) { c_whole = &stagedraw.hud_text.color.active; c_fract = color_mul(color_copy(&c_fract_buf, &stagedraw.hud_text.color.inactive), c_op_mod); } else { @@ -1136,7 +1136,7 @@ static inline void stage_draw_hud_power_value(float xpos, float ypos) { }); draw_fraction( - PLR_MAX_POWER / 100.0, + PLR_MAX_POWER_EFFECTIVE / 100.0, ALIGN_LEFT, xpos, ypos,