#include "comp/entity.h" #include "comp/mechanical.h" #include "comp/physical.h" #include "comp/fighter.h" #include // 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); /* Limit maximum disruption (knockback) when it reaches extremes */ fixed_t dv2 = fmul(m->vdx, m->vdx) + fmul(m->vdy, m->vdy); fixed_t max_dv = limits->max_disruption_speed; if(dv2 > fmul(max_dv, max_dv)) { fixed_t dv = fsqrt(dv2); m->vdx = fmul(fdiv(m->vdx, dv), max_dv); m->vdy = fmul(fdiv(m->vdy, dv), max_dv); } /* 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; vec2 new_pos = { p->x + fmul(m->vx, dt), p->y + fmul(m->vy, dt) }; new_pos = map_move(map, (vec2){ p->x, p->y }, new_pos, p->hitbox); if(f && f->current_attack && f->attack_follows_movement) { physical_t *attack = getcomp(f->current_attack, physical); attack->x += (new_pos.x - p->x); attack->y += (new_pos.y - p->y); } p->x = new_pos.x; p->y = new_pos.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; }