129 lines
3.8 KiB
C
129 lines
3.8 KiB
C
#include "comp/entity.h"
|
|
#include "comp/mechanical.h"
|
|
#include "comp/physical.h"
|
|
#include "comp/fighter.h"
|
|
#include <gint/defs/util.h>
|
|
|
|
// Movement functions
|
|
|
|
void mechanical_move(entity_t *e, vec2 direction, fixed_t dt, map_t const *map)
|
|
{
|
|
physical_t *p = getcomp(e, physical);
|
|
mechanical_t *m = getcomp(e, mechanical);
|
|
fighter_t *f = getcomp(e, fighter);
|
|
mechanical_limits_t const *limits = m->limits;
|
|
|
|
direction = fnormalize(direction);
|
|
|
|
bool stunned = f && f->stun_delay > 0;
|
|
|
|
/* Determine facing */
|
|
int facing = -1;
|
|
bool horz = abs(direction.x) >= abs(direction.y);
|
|
if(direction.x == 0 && direction.y == 0) facing = -1;
|
|
else if( horz && direction.x >= 0) facing = RIGHT;
|
|
else if( horz && direction.x <= 0) facing = LEFT;
|
|
else if(!horz && direction.y <= 0) facing = UP;
|
|
else if(!horz && direction.y >= 0) facing = DOWN;
|
|
|
|
/* Targeted speed, with two components: dash motion and walk motion */
|
|
vec2 target = { 0, 0 };
|
|
|
|
if(m->dash > 0) {
|
|
/* The dash speed is set to one direction and cannot changed */
|
|
vec2 dir = fdir(m->dash_facing);
|
|
target.x += fmul(limits->dash_speed, dir.x);
|
|
target.y += fmul(limits->dash_speed, dir.y);
|
|
}
|
|
if(facing >= 0 && !stunned) {
|
|
/* Walking speed can be directed anywhere, anytime */
|
|
target.x += fmul(limits->max_speed, direction.x);
|
|
target.y += fmul(limits->max_speed, direction.y);
|
|
}
|
|
|
|
/* Friction from environment */
|
|
fixed_t friction_x = fmul(fmul(-target.x, limits->friction), dt);
|
|
fixed_t friction_y = fmul(fmul(-target.y, limits->friction), dt);
|
|
|
|
/* Get there exponentially fast */
|
|
m->vx = target.x + friction_x + m->vdx;
|
|
m->vy = target.y + friction_y + m->vdy;
|
|
|
|
/* Round very small speeds (smaller than 1/256 tiles/s) to 0 */
|
|
if(m->vx >= -256 && m->vx <= 255) m->vx = 0;
|
|
if(m->vy >= -256 && m->vy <= 255) m->vy = 0;
|
|
|
|
/* Decrement time left on the dash */
|
|
m->dash = max(m->dash - dt, fix(0.0));
|
|
|
|
if(facing >= 0)
|
|
p->facing = facing;
|
|
|
|
fixed_t new_x = p->x + fmul(m->vx, dt);
|
|
fixed_t new_y = p->y + fmul(m->vy, dt);
|
|
rect new_hitbox = rect_translate(p->hitbox, (vec2){ new_x, new_y });
|
|
|
|
// TODO ECS: New collision/ejection system based on teleports
|
|
if(!map_collides(map, new_hitbox)) {
|
|
if(f && f->current_attack && f->attack_follows_movement) {
|
|
physical_t *attack = getcomp(f->current_attack, physical);
|
|
attack->x += (new_x - p->x);
|
|
attack->y += (new_y - p->y);
|
|
}
|
|
|
|
p->x = new_x;
|
|
p->y = new_y;
|
|
}
|
|
|
|
/* TODO: Without acceleration, the movement model is broken */
|
|
m->vdx = fmul(m->vdx, fix(0.8));
|
|
m->vdy = fmul(m->vdy, fix(0.8));
|
|
}
|
|
|
|
void mechanical_move4(entity_t *e, int direction, fixed_t dt, map_t const *map)
|
|
{
|
|
return mechanical_move(e, fdir(direction), dt, map);
|
|
}
|
|
|
|
void mechanical_dash(entity_t *e, int direction)
|
|
{
|
|
mechanical_t *m = getcomp(e, mechanical);
|
|
if(m->dash != 0)
|
|
return;
|
|
|
|
m->dash = m->limits->dash_duration;
|
|
m->dash_facing = direction;
|
|
}
|
|
|
|
// Information functions
|
|
|
|
bool mechanical_moving(entity_t const *e)
|
|
{
|
|
mechanical_t *m = getcomp(e, mechanical);
|
|
return (m->vx != 0) || (m->vy != 0);
|
|
}
|
|
|
|
bool mechanical_dashing(entity_t const *e)
|
|
{
|
|
physical_t *p = getcomp(e, physical);
|
|
mechanical_t *m = getcomp(e, mechanical);
|
|
mechanical_limits_t const *limits = m->limits;
|
|
|
|
/* True only if the direction of the dash movement is preserved */
|
|
if(p->facing != m->dash_facing)
|
|
return false;
|
|
|
|
/* True during initial propulsion */
|
|
if(m->dash > 0)
|
|
return true;
|
|
|
|
/* Also true as long as 1.5x over-speed is maintained */
|
|
fixed_t cur_v2 = fmul(m->vx, m->vx) + fmul(m->vy, m->vy);
|
|
fixed_t max_v2 = fmul(limits->max_speed, limits->max_speed);
|
|
|
|
if(2 * cur_v2 > 3 * max_v2)
|
|
return true;
|
|
|
|
return false;
|
|
}
|