This repository has been archived on 2022-05-21. You can view files and clone it, but cannot push or open issues or pull requests.
LEFTONE/core/locharacter/base.c
falsycat 84c3a02b9a [RELEASE] u22-v03
This version is submitted to U22 breau.
2020-09-14 00:00:00 +00:00

435 lines
12 KiB
C

#include "./base.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "util/math/algorithm.h"
#include "util/math/vector.h"
#include "core/lobullet/pool.h"
#include "core/locommon/easing.h"
#include "core/locommon/msgpack.h"
#include "core/locommon/position.h"
#include "core/locommon/ticker.h"
#include "core/loeffect/recipient.h"
#include "core/loentity/character.h"
#include "core/loentity/store.h"
#include "core/loplayer/player.h"
#include "core/loresource/set.h"
#include "core/loshader/character.h"
#include "./big_warder.h"
#include "./cavia.h"
#include "./encephalon.h"
#include "./greedy_scientist.h"
#include "./scientist.h"
#include "./theists_child.h"
#include "./misc.h"
#include "./warder.h"
#define LOCHARACTER_BASE_PARAM_TO_PACK_EACH_( \
PROC, PROC_type, PROC_state, PROC_str) do { \
PROC_str ("subclass", "character"); \
PROC_type ("type", type); \
PROC ("id", super.super.id); \
PROC ("ground", ground); \
PROC ("pos", pos); \
PROC ("direction", direction); \
PROC ("knockback", knockback); \
PROC ("gravity", gravity); \
PROC ("madness", recipient.madness); \
PROC ("effects", recipient.effects); \
PROC_state("state", state); \
PROC ("since", since); \
PROC ("last-update-time", last_update_time); \
PROC ("last-knockback-time", last_knockback_time); \
PROC ("last-hit-time", last_hit_time); \
} while (0)
#define LOCHARACTER_BASE_PARAM_TO_PACK_COUNT 15
static void locharacter_base_convert_to_world_pos_(
const loentity_ground_t* g, locommon_position_t* wpos, const vec2_t* pos) {
assert(g != NULL);
assert(wpos != NULL);
assert(vec2_valid(pos));
vec2_t p = *pos;
p.x *= g->size.x;
p.y += g->size.y;
*wpos = g->super.pos;
vec2_addeq(&wpos->fract, &p);
locommon_position_reduce(wpos);
}
static void locharacter_base_convert_from_world_pos_(
const loentity_ground_t* g, vec2_t* pos, const locommon_position_t* wpos) {
assert(g != NULL);
assert(pos != NULL);
assert(locommon_position_valid(wpos));
locommon_position_sub(pos, wpos, &g->super.pos);
pos->x /= g->size.x;
pos->y -= g->size.y;
}
static loentity_ground_t* locharacter_base_get_ground_(locharacter_base_t* base) {
assert(base != NULL);
loentity_store_iterator_t itr;
if (loentity_store_find_item_by_id(base->entities, &itr, base->ground)) {
return itr.ground;
}
return NULL;
}
static void locharacter_base_handle_knockback_(locharacter_base_t* base) {
assert(base != NULL);
vec2_t v = base->knockback;
v.x /= base->cache.ground->size.x;
vec2_muleq(&v, base->ticker->delta_f);
vec2_addeq(&base->pos, &v);
locommon_easing_linear_float(&base->knockback.x, 0, base->ticker->delta_f/2);
locommon_easing_linear_float(&base->knockback.y, 0, base->ticker->delta_f/2);
}
static void locharacter_base_calculate_world_position_(
locharacter_base_t* base) {
assert(base != NULL);
base->pos.x = MATH_CLAMP(base->pos.x, -1, 1);
base->pos.y = MATH_CLAMP(base->pos.y, 0, 1);
if (base->pos.y < base->cache.height) {
if (base->cache.gravity) base->gravity = 0;
base->pos.y = base->cache.height;
}
locharacter_base_convert_to_world_pos_(
base->cache.ground, &base->super.super.pos, &base->pos);
}
static void locharacter_base_calculate_velocity_(
locharacter_base_t* base, vec2_t* v, const locommon_position_t* oldpos) {
assert(base != NULL);
assert(v != NULL);
assert(locommon_position_valid(oldpos));
locommon_position_sub(v, &base->super.super.pos, oldpos);
vec2_diveq(v, base->ticker->delta_f);
}
static void locharacter_base_execute_bullet_hittest_(
locharacter_base_t* base, const vec2_t* velocity) {
assert(base != NULL);
assert(vec2_valid(velocity));
if (base->last_hit_time + 200 > base->ticker->time) return;
if (loentity_store_affect_bullets_shot_by_one(
base->entities,
&base->super,
base->player->entity.super.super.id,
velocity,
base->ticker->delta_f)) {
base->last_hit_time = base->ticker->time;
}
}
static void locharacter_base_delete_(loentity_t* entity) {
assert(entity != NULL);
locharacter_base_t* base = (typeof(base)) entity;
if (!base->used) return;
base->used = false;
# define each_(NAME, name) do { \
if (base->type == LOCHARACTER_TYPE_##NAME) { \
locharacter_##name##_tear_down(base); \
return; \
} \
} while (0)
LOCHARACTER_TYPE_EACH_(each_);
assert(false);
# undef each_
}
static void locharacter_base_die_(loentity_t* entity) {
assert(entity != NULL);
}
static bool locharacter_base_update_(loentity_t* entity) {
assert(entity != NULL);
static const float gravity_acceleration = 2.f;
locharacter_base_t* base = (typeof(base)) entity;
base->cache = (typeof(base->cache)) {
.time = base->ticker->time,
};
base->cache.ground = locharacter_base_get_ground_(base);
if (base->cache.ground == NULL) return false;
locharacter_base_convert_from_world_pos_(
base->cache.ground,
&base->cache.player_pos,
&base->player->entity.super.super.pos);
locharacter_base_handle_knockback_(base);
locommon_position_t oldpos = base->super.super.pos;
base->pos.y += base->gravity * base->ticker->delta_f;
# define each_(NAME, name) do { \
if (base->type == LOCHARACTER_TYPE_##NAME) { \
if (!locharacter_##name##_update(base)) return false; \
} \
} while (0)
LOCHARACTER_TYPE_EACH_(each_);
# undef each_
locharacter_base_calculate_world_position_(base);
if (base->cache.gravity) {
base->gravity -= base->ticker->delta_f * gravity_acceleration;
} else {
base->gravity = 0;
}
if (base->cache.bullet_hittest) {
vec2_t velocity;
locharacter_base_calculate_velocity_(base, &velocity, &oldpos);
locharacter_base_execute_bullet_hittest_(base, &velocity);
}
base->cache.ground = NULL;
base->last_update_time = base->cache.time;
return true;
}
static void locharacter_base_draw_(
loentity_t* entity, const locommon_position_t* basepos) {
assert(entity != NULL);
assert(locommon_position_valid(basepos));
locharacter_base_t* base = (typeof(base)) entity;
vec2_t v;
locommon_position_sub(&v, &base->super.super.pos, basepos);
vec2_addeq(&base->cache.instance.pos, &v);
loshader_character_drawer_add_instance(base->drawer, &base->cache.instance);
}
static void locharacter_base_apply_effect_(
loentity_character_t* entity, const loeffect_t* effect) {
assert(entity != NULL);
assert(effect != NULL);
locharacter_base_t* base = (typeof(base)) entity;
loeffect_recipient_apply_effect(&base->recipient, effect);
}
static void locharacter_base_knockback_(
loentity_character_t* chara, const vec2_t* knockback) {
assert(chara != NULL);
assert(vec2_valid(knockback));
locharacter_base_t* base = (typeof(base)) chara;
static const float r = .05f;
if (vec2_pow_length(knockback) > r*r) {
base->last_knockback_time = base->ticker->time;
}
vec2_addeq(&base->knockback, knockback);
}
static void locharacter_base_pack_(
const loentity_t* chara, msgpack_packer* packer) {
assert(chara != NULL);
assert(packer != NULL);
const locharacter_base_t* base = (typeof(base)) chara;
msgpack_pack_map(packer, LOCHARACTER_BASE_PARAM_TO_PACK_COUNT+1);
# define pack_(name, var) do { \
mpkutil_pack_str(packer, name); \
LOCOMMON_MSGPACK_PACK_ANY(packer, &base->var); \
} while (0)
# define pack_type_(name, var) do { \
mpkutil_pack_str(packer, name); \
mpkutil_pack_str(packer, locharacter_type_stringify(base->var)); \
} while (0)
# define pack_state_(name, var) do { \
mpkutil_pack_str(packer, name); \
mpkutil_pack_str(packer, locharacter_state_stringify(base->var)); \
} while (0)
# define pack_str_(name, str) do { \
mpkutil_pack_str(packer, name); \
mpkutil_pack_str(packer, str); \
} while (0)
LOCHARACTER_BASE_PARAM_TO_PACK_EACH_(pack_, pack_type_, pack_state_, pack_str_);
# undef pack_str_
# undef pack_state_
# undef pack_type_
# undef pack_
# define each_(NAME, name) do { \
if (base->type == LOCHARACTER_TYPE_##NAME) { \
locharacter_##name##_pack_data(base, packer); \
return; \
} \
} while (0)
mpkutil_pack_str(packer, "data");
LOCHARACTER_TYPE_EACH_(each_);
assert(false);
# undef each_
}
void locharacter_base_initialize(
locharacter_base_t* base,
loresource_set_t* res,
loshader_character_drawer_t* drawer,
const locommon_ticker_t* ticker,
lobullet_pool_t* bullets,
loentity_store_t* entities,
loplayer_t* player) {
assert(base != NULL);
assert(res != NULL);
assert(drawer != NULL);
assert(ticker != NULL);
assert(bullets != NULL);
assert(entities != NULL);
assert(player != NULL);
*base = (typeof(*base)) {
.super = {
.super = {
.vtable = {
.delete = locharacter_base_delete_,
.die = locharacter_base_die_,
.update = locharacter_base_update_,
.draw = locharacter_base_draw_,
.pack = locharacter_base_pack_,
},
.subclass = LOENTITY_SUBCLASS_CHARACTER,
},
.vtable = {
.apply_effect = locharacter_base_apply_effect_,
.knockback = locharacter_base_knockback_,
},
},
.res = res,
.drawer = drawer,
.ticker = ticker,
.bullets = bullets,
.entities = entities,
.player = player,
};
loeffect_recipient_initialize(&base->recipient, ticker);
}
void locharacter_base_reinitialize(locharacter_base_t* base, loentity_id_t id) {
assert(base != NULL);
# define reset_(name, var) do { \
base->var = (typeof(base->var)) {0}; \
} while (0)
# define reset_str_(name, str)
LOCHARACTER_BASE_PARAM_TO_PACK_EACH_(
reset_, reset_, reset_, reset_str_);
# undef reset_str_
# undef reset_
loeffect_recipient_reset(&base->recipient);
base->super.super.id = id;
}
void locharacter_base_deinitialize(locharacter_base_t* base) {
assert(base != NULL);
if (base->used) locharacter_base_delete_(&base->super.super);
loeffect_recipient_deinitialize(&base->recipient);
}
bool locharacter_base_unpack(
locharacter_base_t* base, const msgpack_object* obj) {
assert(base != NULL);
assert(obj != NULL);
locharacter_base_reinitialize(base, 0);
/* id will be overwritten below */
const char* v;
size_t vlen;
const msgpack_object_map* root = mpkutil_get_map(obj);
# define item_(v) mpkutil_get_map_item_by_str(root, v)
# define unpack_(name, var) do { \
if (!LOCOMMON_MSGPACK_UNPACK_ANY(item_(name), &base->var)) { \
return NULL; \
} \
} while (0)
# define unpack_type_(name, var) do { \
if (!mpkutil_get_str(item_(name), &v, &vlen) || \
!locharacter_type_unstringify(&base->var, v, vlen)) { \
return NULL; \
} \
} while (0)
# define unpack_state_(name, var) do { \
if (!mpkutil_get_str(item_(name), &v, &vlen) || \
!locharacter_state_unstringify(&base->var, v, vlen)) { \
return NULL; \
} \
} while (0)
# define unpack_str_(name, str) do { \
if (!mpkutil_get_str(item_(name), &v, &vlen) || \
!(strncmp(v, str, vlen) == 0 && str[vlen] == 0)) { \
return NULL; \
} \
} while (0)
LOCHARACTER_BASE_PARAM_TO_PACK_EACH_(
unpack_, unpack_type_, unpack_state_, unpack_str_);
# undef unpack_str_
# undef unpack_state_
# undef unpack_type_
# undef unpack_
const msgpack_object* data = item_("data");
# define each_(NAME, name) do { \
if (base->type == LOCHARACTER_TYPE_##NAME) { \
return locharacter_##name##_unpack_data(base, data); \
} \
} while (0)
LOCHARACTER_TYPE_EACH_(each_);
return false;
# undef each_
# undef item_
}