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/warder.c

300 lines
8.8 KiB
C
Raw Normal View History

#include "./warder.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include "util/math/algorithm.h"
#include "util/math/vector.h"
#include "core/lobullet/base.h"
#include "core/lobullet/linear.h"
#include "core/loeffect/recipient.h"
#include "core/loentity/entity.h"
#include "core/loentity/store.h"
#include "core/loplayer/event.h"
#include "core/loplayer/player.h"
#include "core/loresource/sound.h"
#include "core/loshader/character.h"
#include "./base.h"
#include "./misc.h"
static const vec2_t locharacter_warder_size_ = vec2(.02f, .05f);
static const loeffect_recipient_status_t locharacter_warder_base_status_ = {
.attack = .1f,
.defence = -.8f,
};
static void locharacter_warder_shoot_(locharacter_base_t* c) {
assert(c != NULL);
lobullet_base_t* b = lobullet_pool_create(c->bullets);
lobullet_linear_light_build(b, (&(lobullet_linear_param_t) {
.owner = c->super.super.id,
.pos = c->super.super.pos,
.size = vec2(.04f, .04f),
.velocity = vec2(c->direction*.5f, 0),
.color = vec4(.6f, .6f, .6f, .8f),
.acceleration = vec2(0, 0),
.duration = 2000,
.knockback = .4f,
.effect = loeffect_immediate_damage(c->recipient.status.attack),
}));
loentity_store_add(c->entities, &b->super.super);
loresource_sound_play(c->res->sound, "enemy_shoot");
}
static void
locharacter_warder_start_wait_state_(
locharacter_base_t* base
);
static void
locharacter_warder_start_shoot_state_(
locharacter_base_t* base
);
static void
locharacter_warder_start_combo_state_(
locharacter_base_t* base
);
static void
locharacter_warder_start_dead_state_(
locharacter_base_t* base
);
static void locharacter_warder_update_wait_state_(locharacter_base_t* base) {
assert(base != NULL);
static const uint64_t duration = 1000;
const uint64_t elapsed = base->ticker->time - base->since;
/* ---- motion ---- */
float t = elapsed*1.f / duration;
if (t > 1) t = 1;
loshader_character_drawer_instance_t* instance = &base->cache.instance;
instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2;
instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1;
instance->motion_time = t*t*(3-2*t);
/* ---- state transition ---- */
if (elapsed >= duration) {
if (base->recipient.madness <= 0) {
locharacter_warder_start_dead_state_(base);
return;
}
if (loplayer_event_get_param(base->player->event) == NULL) {
vec2_t disp;
vec2_sub(&disp, &base->cache.player_pos, &base->pos);
disp.x *= base->cache.ground->size.x;
const float pdist = vec2_pow_length(&disp);
if (MATH_ABS(disp.y) < locharacter_warder_size_.y && pdist < .4f*.4f) {
static const float r = locharacter_warder_size_.x*3;
if (pdist < r*r) {
locharacter_warder_start_combo_state_(base);
} else if (disp.x*base->direction > 0) {
locharacter_warder_start_shoot_state_(base);
}
}
return;
}
}
}
static void locharacter_warder_start_wait_state_(locharacter_base_t* base) {
assert(base != NULL);
base->since = base->ticker->time;
base->state = LOCHARACTER_STATE_WAIT;
}
static void locharacter_warder_update_shoot_state_(locharacter_base_t* base) {
assert(base != NULL);
static const uint64_t duration = 500;
const uint64_t elapsed = base->ticker->time - base->since;
/* ---- motion ---- */
float t = elapsed*1.f / duration;
if (t > 1) t = 1;
t = t*t;
loshader_character_drawer_instance_t* instance = &base->cache.instance;
if (t < .5f) {
instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1;
instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1;
instance->motion_time = t*2;
} else {
instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1;
instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2;
instance->motion_time = (t-.5f)*2;
}
/* ---- state transition ---- */
if (elapsed >= duration) {
locharacter_warder_shoot_(base);
locharacter_warder_start_wait_state_(base);
return;
}
}
static void locharacter_warder_start_shoot_state_(locharacter_base_t* base) {
assert(base != NULL);
base->since = base->ticker->time;
base->state = LOCHARACTER_STATE_SHOOT;
}
static void locharacter_warder_update_combo_state_(locharacter_base_t* base) {
assert(base != NULL);
static const uint64_t duration = 1000;
const uint64_t elapsed = base->ticker->time - base->since;
/* ---- motion ---- */
float t = elapsed*1.f/duration;
if (t > 1) t = 1;
t = t*t;
loshader_character_drawer_instance_t* instance = &base->cache.instance;
if (t < .5f) {
instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1;
instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1;
instance->motion_time = t*2;
} else {
instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK1;
instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2;
instance->motion_time = (t-.5f)*2;
}
/* ---- state transition ---- */
if (elapsed >= duration) {
locharacter_warder_start_wait_state_(base);
return;
}
}
static void locharacter_warder_start_combo_state_(locharacter_base_t* base) {
assert(base != NULL);
base->since = base->ticker->time;
base->state = LOCHARACTER_STATE_COMBO;
const float diff = base->cache.player_pos.x - base->pos.x;
base->direction = MATH_SIGN(diff);
const loplayer_combat_attack_t attack = {
.attacker = base->super.super.id,
.start = base->ticker->time + 500,
.duration = 500,
.knockback = vec2(base->direction*.1f, 0),
.effect = loeffect_immediate_damage(base->recipient.status.attack),
};
loplayer_attack(base->player, &attack);
}
static void locharacter_warder_update_dead_state_(locharacter_base_t* base) {
assert(base != NULL);
static const uint64_t anime_duration = 500;
static const uint64_t duration = 30000;
const uint64_t elapsed = base->ticker->time - base->since;
/* ---- motion ---- */
loshader_character_drawer_instance_t* instance = &base->cache.instance;
if (elapsed > duration - anime_duration) { /* wake up */
float t = 1-(duration - elapsed)*1.f/anime_duration;
if (t < 0) t = 0;
instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN;
instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_STAND1;
instance->motion_time = 1-powf(1-t, 2);
} else { /* down */
float t = elapsed*1.f/anime_duration;
if (t > 1) t = 1;
instance->from_motion_id = LOSHADER_CHARACTER_MOTION_ID_ATTACK2;
instance->to_motion_id = LOSHADER_CHARACTER_MOTION_ID_DOWN;
instance->motion_time = t;
}
/* ---- state transition ---- */
if (elapsed >= duration) {
loeffect_recipient_reset(&base->recipient);
locharacter_warder_start_wait_state_(base);
return;
}
}
static void locharacter_warder_start_dead_state_(locharacter_base_t* base) {
assert(base != NULL);
base->since = base->ticker->time;
base->state = LOCHARACTER_STATE_DEAD;
loplayer_gain_faith(base->player, .1f);
}
bool locharacter_warder_update(locharacter_base_t* base) {
assert(base != NULL);
static const vec2_t size = locharacter_warder_size_;
static const vec4_t color = vec4(.1f, .1f, .1f, 1);
static const float height = size.y*1.4f;
static const float drawsz = MATH_MAX(size.x, size.y);
loeffect_recipient_update(&base->recipient, &locharacter_warder_base_status_);
base->cache.instance = (loshader_character_drawer_instance_t) {
.character_id = LOSHADER_CHARACTER_ID_WARDER,
.marker_offset = vec2(0, height - drawsz),
.pos = vec2(0, drawsz - height),
.size = vec2(drawsz, drawsz),
.color = color,
};
switch (base->state) {
case LOCHARACTER_STATE_WAIT:
locharacter_warder_update_wait_state_(base);
break;
case LOCHARACTER_STATE_SHOOT:
locharacter_warder_update_shoot_state_(base);
break;
case LOCHARACTER_STATE_COMBO:
locharacter_warder_update_combo_state_(base);
break;
case LOCHARACTER_STATE_DEAD:
locharacter_warder_update_dead_state_(base);
break;
default:
locharacter_warder_start_wait_state_(base);
}
base->cache.bullet_hittest = base->state != LOCHARACTER_STATE_DEAD;
base->cache.gravity = true;
base->cache.height = height;
base->cache.instance.size.x *= base->direction;
base->cache.instance.marker = !!base->cache.bullet_hittest;
return true;
}
void locharacter_warder_build(
locharacter_base_t* base, const locharacter_warder_param_t* param) {
assert(base != NULL);
assert(param != NULL);
base->type = LOCHARACTER_TYPE_WARDER;
base->ground = param->ground;
base->pos = vec2(param->pos, 0);
base->direction = -MATH_SIGN(param->pos);
if (base->direction == 0) base->direction = 1;
locharacter_warder_start_wait_state_(base);
}