taisei/src/player.h
2024-05-17 14:11:48 +02:00

254 lines
6.6 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#pragma once
#include "taisei.h"
#include "aniplayer.h"
#include "color.h"
#include "coroutine/coevent.h"
#include "entity.h"
#include "replay/eventcodes.h"
#include "replay/state.h"
#include "resource/resource.h"
#include "stats.h"
#ifdef DEBUG
#define PLR_DPS_STATS
#endif
#ifdef PLR_DPS_STATS
#define IF_PLR_DPS_STATS(...) __VA_ARGS__
#else
#define IF_PLR_DPS_STATS(...)
#endif
enum {
PLR_MAX_POWER_EFFECTIVE = 400,
PLR_MAX_POWER_STORED = 600,
PLR_MAX_LIVES = 8,
PLR_MAX_BOMBS = 8,
// -Wpedantic doesn't like this
// PLR_MAX_PIV = UINT32_MAX,
#define PLR_MAX_PIV UINT32_MAX
#define PLR_MAX_GRAZE UINT32_MAX
#define PLR_MAX_VOLTAGE UINT16_MAX
PLR_MAX_LIFE_FRAGMENTS = 5,
PLR_MAX_BOMB_FRAGMENTS = 500,
PLR_START_LIVES = 2,
PLR_START_BOMBS = 3,
PLR_START_PIV = 10000,
PLR_STGPRACTICE_LIVES = PLR_MAX_LIVES,
PLR_STGPRACTICE_BOMBS = PLR_START_BOMBS,
PLR_MIN_BORDER_DIST = 16,
PLR_POWERSURGE_POWERCOST = 200,
PLR_RESPAWN_TIME = 60,
PLR_RECOVERY_TIME = 210,
};
#define PLR_SPAWN_POS_X (VIEWPORT_W * 0.5)
#define PLR_SPAWN_POS_Y (VIEWPORT_H - 64.0)
#define PLR_SPAWN_POS CMPLX(PLR_SPAWN_POS_X, PLR_SPAWN_POS_Y)
static const float PLR_POWERSURGE_POSITIVE_DRAIN_MAX = (0.15 / 60.0);
static const float PLR_POWERSURGE_POSITIVE_DRAIN_MIN = (0.15 / 60.0);
static const float PLR_POWERSURGE_NEGATIVE_DRAIN_MAX = (0.15 / 60.0);
static const float PLR_POWERSURGE_NEGATIVE_DRAIN_MIN = (0.01 / 60.0);
static const float PLR_POWERSURGE_POSITIVE_GAIN = (1.50 / 60.0);
static const float PLR_POWERSURGE_NEGATIVE_GAIN = (0.40 / 60.0);
// do not reorder these or you'll break replays
#define INFLAGS \
INFLAG(UP, 0) \
INFLAG(DOWN, 1) \
INFLAG(LEFT, 2) \
INFLAG(RIGHT, 3) \
INFLAG(FOCUS, 4) \
INFLAG(SHOT, 5) \
INFLAG(SKIP, 6) \
typedef enum {
#define INFLAG(name, bit) \
INFLAG_##name = (1 << bit),
INFLAGS
#undef INFLAG
} PlrInputFlag;
enum {
INFLAGS_MOVE = INFLAG_UP | INFLAG_DOWN | INFLAG_LEFT | INFLAG_RIGHT
};
typedef struct PowerSurgeBonus {
uint baseline;
uint score;
uint gain_rate;
float discharge_power;
float discharge_range;
float discharge_damage;
} PowerSurgeBonus;
DEFINE_ENTITY_TYPE(Player, {
cmplx pos;
cmplx velocity;
cmplx uncapped_velocity;
cmplx deathpos;
struct PlayerMode *mode;
AniPlayer ani;
Sprite bomb_portrait;
Stats stats;
struct {
float positive;
float negative;
struct {
int activated, expired;
} time;
int total_charge;
int player_power;
double damage_done;
double damage_accum;
PowerSurgeBonus bonus;
} powersurge;
COEVENTS_ARRAY(
shoot,
inputflags_changed,
stored_power_changed,
effective_power_changed,
bomb_used
) events;
uint64_t points;
uint64_t extralife_threshold;
uint extralives_given;
uint point_item_value;
uint graze;
uint voltage;
int lives;
int bombs;
int life_fragments;
int bomb_fragments;
int power_stored;
int _prev_effective_power;
int continuetime;
int deathtime; /* time of hit + deathbomb window */
int respawntime; /* end of respawn animation; control returns to player */
int recoverytime; /* end of post-death i-frames */
int bomb_triggertime; /* time when the bomb was triggered */
int bomb_endtime; /* time when the bomb i-frames end */
uint inputflags;
int lastmovesequence; // used for animation
int axis_ud;
int axis_lr;
float focus_circle_alpha;
float bomb_cutin_alpha;
bool gamepadmove;
bool iddqd;
IF_PLR_DPS_STATS(
int dmglogframe;
int dmglog[240];
)
});
typedef enum PlayerEventResult {
PLREVT_USEFUL = (1 << 0),
PLREVT_CHEAT = (1 << 1),
} PlayerEventResult;
// This is called first before we even enter stage_loop.
// It's also called right before syncing player state from a replay stage struct, if a replay is being watched or recorded, before every stage.
// The entire state is reset here, and defaults for story mode are set.
void player_init(Player *plr);
// This is called early in stage_loop, before creating or reading replay stage data.
// State that is not supposed to be preserved between stages is reset here, and any plrmode-specific resources are preloaded.
void player_stage_pre_init(Player *plr);
// This is called right after the stage's begin proc. After that, the actual game loop starts.
void player_stage_post_init(Player *plr);
// Yes, that's 3 different initialization functions right here.
void player_free(Player *plr);
void player_draw_overlay(Player *plr);
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);
void player_realdeath(Player*);
void player_death(Player*);
void player_graze(Player *plr, cmplx pos, int pts, int effect_intensity, const Color *color);
PlayerEventResult player_event(
Player *plr,
ReplayState *rpy_in,
ReplayState *rpy_out,
ReplayEventCode type,
uint16_t value
) attr_nonnull(1);
void player_fix_input(Player *plr, ReplayState *rpy_out);
void player_applymovement(Player* plr);
void player_add_life_fragments(Player *plr, int frags);
void player_add_bomb_fragments(Player *plr, int frags);
void player_add_lives(Player *plr, int lives);
void player_add_bombs(Player *plr, int bombs);
void player_add_points(Player *plr, uint points, cmplx location);
void player_add_piv(Player *plr, uint piv, cmplx location);
void player_add_voltage(Player *plr, uint voltage);
bool player_drain_voltage(Player *plr, uint voltage);
void player_extend_powersurge(Player *plr, float pos, float neg);
void player_register_damage(Player *plr, EntityInterface *target, const DamageInfo *damage);
void player_cancel_powersurge(Player *plr);
void player_placeholder_bomb_logic(Player *plr);
bool player_is_recovering(Player *plr);
bool player_is_bomb_active(Player *plr);
bool player_is_powersurge_active(Player *plr);
bool player_is_vulnerable(Player *plr);
bool player_is_alive(Player *plr);
void player_powersurge_calc_bonus(Player *plr, PowerSurgeBonus *bonus);
uint64_t player_next_extralife_threshold(uint64_t step);
// Progress is normalized from 0: bomb start to 1: bomb end
double player_get_bomb_progress(Player *plr);
void player_damage_hook(Player *plr, EntityInterface *target, DamageInfo *dmg);
void player_preload(ResourceGroup *rg);
// FIXME: where should this be?
cmplx plrutil_homing_target(cmplx org, cmplx fallback);
void plrutil_slave_retract(BoxedPlayer bplr, cmplx *pos, real retract_time);