254 lines
6.6 KiB
C
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);
|