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/lochara/strategy.c

185 lines
5.0 KiB
C
Raw Permalink Normal View History

#include "./strategy.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "util/chaos/xorshift.h"
#include "util/math/algorithm.h"
#include "util/math/vector.h"
#include "util/statman/statman.h"
#include "core/loeffect/effect.h"
#include "core/loeffect/recipient.h"
#include "./base.h"
#include "./combat.h"
#include "./state.h"
#define SEED_ 3467
#define PARRY_DAMAGE_ 1
void lochara_strategy_initialize_any_(
const statman_meta_t* meta, void* instance, statman_state_t* next) {
assert(meta != NULL);
assert(instance != NULL);
assert(next != NULL);
lochara_base_t* base = instance;
base->param.last_strategy_changed = base->ticker->time;
}
void lochara_strategy_cancel_transition_(
const statman_meta_t* meta, void* instance, statman_state_t* next) {
assert(meta != NULL);
assert(instance != NULL);
assert(next != NULL);
*next = meta->state;
}
void lochara_strategy_initialize_scouting_(
const statman_meta_t* meta, void* instance, statman_state_t* next) {
assert(meta != NULL);
assert(instance != NULL);
assert(next != NULL);
lochara_strategy_initialize_any_(meta, instance, next);
const lochara_strategy_scouting_param_t* p = meta->data;
lochara_base_t* base = instance;
statman_transition_to(
p->state_table, base, &base->param.state, LOCHARA_STATE_STAND);
}
void lochara_strategy_update_scouting_(
const statman_meta_t* meta, void* instance, statman_state_t* next) {
assert(meta != NULL);
assert(instance != NULL);
assert(next != NULL);
const lochara_strategy_scouting_param_t* p = meta->data;
assert(p->state_table != NULL);
assert(p->period > 0);
lochara_base_t* base = instance;
const uint64_t t = base->ticker->time;
const bool knockback = base->param.last_knockback+500 > t;
const bool event = base->player->event.executor != 0;
/* ---- die ---- */
if (!loeffect_recipient_is_alive(&base->param.recipient)) {
*next = LOCHARA_STRATEGY_DEAD;
return;
}
/* ---- strategy transition ---- */
vec2_t disp;
locommon_position_sub(
&disp, &base->player->entity->super.super.pos, &base->super.super.pos);
if (!knockback && MATH_ABS(disp.y) < .1f && !event) {
disp.x *= MATH_SIGN_NOZERO(base->param.direction.x);
const float b = p->range_back;
if (-p->range_close*b < disp.x && disp.x < p->range_close) {
*next = p->found_close;
} else if (-p->range_mid*b < disp.x && disp.x < p->range_mid) {
*next = p->found_mid;
} else if (-p->range_long*b < disp.x && disp.x < p->range_long) {
*next = p->found_long;
}
if (*next != LOCHARA_STRATEGY_SCOUTING) return;
}
/* ---- state transition ---- */
const uint64_t since = base->param.last_state_changed;
uint64_t seed = 1+since*SEED_;
# define rand_() (seed = chaos_xorshift(seed))
const uint64_t dur = rand_()%p->period + p->period/2;
lochara_state_t state = base->param.state;
if (knockback) {
state = LOCHARA_STATE_STAND;
} else if (since+dur < t) {
seed = 1+t*SEED_;
if (state == LOCHARA_STATE_STAND && rand_()%100/100.f < p->stagger) {
const float r = .5f + base->cache.ground_pos.x*.5f;
if (rand_()%100/100.f < r) {
base->param.direction = vec2(-1, 0);
state = LOCHARA_STATE_WALK_LEFT;
} else {
base->param.direction = vec2(1, 0);
state = LOCHARA_STATE_WALK_RIGHT;
}
} else {
state = LOCHARA_STATE_STAND;
}
}
statman_transition_to(p->state_table, base, &base->param.state, state);
# undef rand_
}
void lochara_strategy_initialize_combat_(
const statman_meta_t* meta, void* instance, statman_state_t* next) {
assert(meta != NULL);
assert(instance != NULL);
assert(next != NULL);
lochara_base_t* base = instance;
const lochara_strategy_combat_param_t* p = meta->data;
assert(p->actions != NULL);
if (base->param.last_knockback+p->parry_window > base->ticker->time) {
loentity_character_apply_effect(
&base->super, &loeffect_damage(PARRY_DAMAGE_));
*next = p->parried_next;
return;
}
lochara_strategy_initialize_any_(meta, instance, next);
lochara_combat_action_execute_all_attacks(p->actions, base);
vec2_t disp;
locommon_position_sub(
&disp, &base->player->entity->super.super.pos, &base->super.super.pos);
base->param.direction = vec2(MATH_SIGN_NOZERO(disp.x), 0);
}
void lochara_strategy_update_combat_(
const statman_meta_t* meta, void* instance, statman_state_t* next) {
assert(meta != NULL);
assert(instance != NULL);
assert(next != NULL);
const lochara_strategy_combat_param_t* p = meta->data;
assert(p->actions != NULL);
assert(p->next != meta->state);
lochara_base_t* base = instance;
if (!p->gravity) base->param.gravity = 0;
const uint64_t t = base->ticker->time - base->param.last_strategy_changed;
const lochara_combat_action_t* action =
lochara_combat_action_find_by_time(p->actions, t);
if (action == NULL) {
*next = p->next;
return;
}
statman_transition_to(
p->state_table, base, &base->param.state, action->state);
}