Training dummy leans with knockback, blast pushes, Vacuum suction and gusts
Hits tip it by their actual knockback (shared with fighters through knock_get), blasts push it, a Vacuum pulls it toward its wielder and an airblast shoves it away. Blocks stay still. Protocol 7.
This commit is contained in:
1 parent
b96defa1e6
commit
f4e7784f3c
4 files changed
+52
-13
No files matched your search
+11
-5
@@ -127,6 +127,15 @@ void Fighter::state_reset(Sim& sim, float maxHealth)
|
|||||||
isAlive = true;
|
isAlive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The knock a hit gives whatever it lands on, centred at center: away from where it came from (and a little upward), at
|
||||||
|
// a speed that grows with the damage, times the hit's own knock.
|
||||||
|
Vec2 knock_get(Damage& damage, Vec2 center)
|
||||||
|
{
|
||||||
|
Vec2 away = center - damage.source;
|
||||||
|
Vec2 direction = vec2_normalize(vec2_normalize(vec2_length(away) > 1 ? away : Vec2{0, -1}) + Vec2{0, -KNOCK_LIFT});
|
||||||
|
return direction * std::min(KNOCK_MAX, KNOCK_BASE + damage.amount * KNOCK_PER_DAMAGE) * damage.knock;
|
||||||
|
}
|
||||||
|
|
||||||
// Loses health with a flash and hitstop, and gets knocked away from where the hit came from (and a little upward),
|
// Loses health with a flash and hitstop, and gets knocked away from where the hit came from (and a little upward),
|
||||||
// up to a speed that grows with the damage (see knock_take). Shock Absorber softens it. Running out of health kills it
|
// up to a speed that grows with the damage (see knock_take). Shock Absorber softens it. Running out of health kills it
|
||||||
// in a burst, and its attacks vanish with it.
|
// in a burst, and its attacks vanish with it.
|
||||||
@@ -138,11 +147,8 @@ void Fighter::damage_take(Sim& sim, Damage damage)
|
|||||||
flash = 1;
|
flash = 1;
|
||||||
hitstop_add(damage.hitstop);
|
hitstop_add(damage.hitstop);
|
||||||
|
|
||||||
Vec2 away = center_get() - damage.source;
|
float taken = (isRacing ? RACE_KNOCK : 1) * stat_get(STAT_KNOCKBACK_TAKEN);
|
||||||
Vec2 direction = vec2_normalize(vec2_normalize(vec2_length(away) > 1 ? away : Vec2{0, -1}) + Vec2{0, -KNOCK_LIFT});
|
knock_take(knock_get(damage, center_get()) * taken, damage.owner);
|
||||||
float knock = std::min(KNOCK_MAX, KNOCK_BASE + damage.amount * KNOCK_PER_DAMAGE) * damage.knock *
|
|
||||||
(isRacing ? RACE_KNOCK : 1) * stat_get(STAT_KNOCKBACK_TAKEN);
|
|
||||||
knock_take(direction * knock, damage.owner);
|
|
||||||
if (health > 0)
|
if (health > 0)
|
||||||
return;
|
return;
|
||||||
die(sim);
|
die(sim);
|
||||||
|
|||||||
@@ -98,6 +98,9 @@ constexpr float CHARGE_VISIBLE = 0.15f;
|
|||||||
// knock it about (half as hard), and touching a pit puts it back on the last ground it stood squarely on. Slopes slow
|
// knock it about (half as hard), and touching a pit puts it back on the last ground it stood squarely on. Slopes slow
|
||||||
// it climbing and speed it up descending. Crouching on one slides it down, rolling, and the slide carries on over flat
|
// it climbing and speed it up descending. Crouching on one slides it down, rolling, and the slide carries on over flat
|
||||||
// ground until it slows.
|
// ground until it slows.
|
||||||
|
struct Damage;
|
||||||
|
Vec2 knock_get(Damage& damage, Vec2 center);
|
||||||
|
|
||||||
class Fighter
|
class Fighter
|
||||||
{
|
{
|
||||||
friend class Scene;
|
friend class Scene;
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
constexpr int PROTOCOL_VERSION = 6;
|
constexpr int PROTOCOL_VERSION = 7;
|
||||||
constexpr int LOBBY_MEMBERS_MAX = 16;
|
constexpr int LOBBY_MEMBERS_MAX = 16;
|
||||||
constexpr int LOBBY_CODE_LENGTH = 4;
|
constexpr int LOBBY_CODE_LENGTH = 4;
|
||||||
// Letters only, without I and O, so codes are easy to read out and type.
|
// Letters only, without I and O, so codes are easy to read out and type.
|
||||||
|
|||||||
+37
-7
@@ -85,7 +85,10 @@ constexpr float WHIP_WOBBLES = 1;
|
|||||||
constexpr float WHIP_DAMPING = 0.02f;
|
constexpr float WHIP_DAMPING = 0.02f;
|
||||||
constexpr float WHIP_SAG = 0.6f;
|
constexpr float WHIP_SAG = 0.6f;
|
||||||
constexpr float WHIP_PULL = 220;
|
constexpr float WHIP_PULL = 220;
|
||||||
constexpr float WOBBLE_IMPULSE = 0.15f;
|
// How far a push tips a dummy: its sideways speed into lean speed for a sudden push (a hit or a blast), and its
|
||||||
|
// sideways acceleration into lean acceleration for a steady one (a Vacuum's pull).
|
||||||
|
constexpr float WOBBLE_PER_SPEED = 0.005f;
|
||||||
|
constexpr float WOBBLE_PER_PULL = 0.05f;
|
||||||
// Vacuum: how fast its pull speeds fighters and shots up toward it, how much of an airblast's knock is left at the edge
|
// Vacuum: how fast its pull speeds fighters and shots up toward it, how much of an airblast's knock is left at the edge
|
||||||
// of its reach, and how much of it shoves shots.
|
// of its reach, and how much of it shoves shots.
|
||||||
constexpr float VACUUM_PULL_RATE = 900;
|
constexpr float VACUUM_PULL_RATE = 900;
|
||||||
@@ -1607,6 +1610,14 @@ void Weapons::attack_hit(Sim& sim, Attack& attack, int target, Vec2 point)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tips a dummy the way a sudden push goes (a block, which never leans, ignores it), by its sideways part: a dummy
|
||||||
|
// stands on its stand, so only its lean feels the push.
|
||||||
|
static void dummy_push(Dummy& dummy, Vec2 push)
|
||||||
|
{
|
||||||
|
if (dummy.tile < 0)
|
||||||
|
dummy.wobbleSpeed += push.x * WOBBLE_PER_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
// Hurts a target with all the feedback: sparks, a number, shake that grows with the damage and a sound. The attacker
|
// Hurts a target with all the feedback: sparks, a number, shake that grows with the damage and a sound. The attacker
|
||||||
// freezes in hitstop, its Boxing Glove adds to the knock, and its Embiggener to the damage.
|
// freezes in hitstop, its Boxing Glove adds to the knock, and its Embiggener to the damage.
|
||||||
// Dummies flash and wobble, blocks crack and break, and fighters take the damage themselves. In a race, fighters only
|
// Dummies flash and wobble, blocks crack and break, and fighters take the damage themselves. In a race, fighters only
|
||||||
@@ -1627,7 +1638,7 @@ void Weapons::damage_deal(Sim& sim, Damage damage)
|
|||||||
{
|
{
|
||||||
Dummy& dummy = sim.world.dummies[damage.target - MAX_FIGHTERS];
|
Dummy& dummy = sim.world.dummies[damage.target - MAX_FIGHTERS];
|
||||||
dummy.flash = 1;
|
dummy.flash = 1;
|
||||||
dummy.wobbleSpeed += side * WOBBLE_IMPULSE * damage.amount;
|
dummy_push(dummy, knock_get(damage, {box.x + box.w / 2, box.y + box.h / 2}));
|
||||||
dummy.health -= damage.amount;
|
dummy.health -= damage.amount;
|
||||||
if (dummy.tile >= 0 && dummy.health <= 0)
|
if (dummy.tile >= 0 && dummy.health <= 0)
|
||||||
sim.world.block_break(sim, dummy, damage.owner);
|
sim.world.block_break(sim, dummy, damage.owner);
|
||||||
@@ -2052,6 +2063,13 @@ void Weapons::blast_spawn(Sim& sim, Blast blast)
|
|||||||
vec2_normalize(distance > 0 ? away : Vec2{0, -1}) * KNOCKBACK_SPEED * (1 - distance / reach) * absorb;
|
vec2_normalize(distance > 0 ? away : Vec2{0, -1}) * KNOCKBACK_SPEED * (1 - distance / reach) * absorb;
|
||||||
fighter.impulse_add(push);
|
fighter.impulse_add(push);
|
||||||
}
|
}
|
||||||
|
for (Dummy& dummy : sim.world.dummies)
|
||||||
|
{
|
||||||
|
Vec2 away = Vec2{dummy.box.x + dummy.box.w / 2, dummy.box.y + dummy.box.h / 2} - blast.position;
|
||||||
|
float distance = vec2_length(away);
|
||||||
|
if (blast.isPushing && distance < reach)
|
||||||
|
dummy_push(dummy, vec2_normalize(away) * KNOCKBACK_SPEED * (1 - distance / reach) * boxing);
|
||||||
|
}
|
||||||
|
|
||||||
Attack attack = {
|
Attack attack = {
|
||||||
.stats = {.damage = blast.damage, .range = blast.area},
|
.stats = {.damage = blast.damage, .range = blast.area},
|
||||||
@@ -2283,6 +2301,15 @@ void Weapons::vacuum_move(Sim& sim, Attack& attack)
|
|||||||
float pull = std::min(room, VACUUM_PULL_RATE * boxing * TICK) * target.stat_get(STAT_KNOCKBACK_TAKEN);
|
float pull = std::min(room, VACUUM_PULL_RATE * boxing * TICK) * target.stat_get(STAT_KNOCKBACK_TAKEN);
|
||||||
target.body.velocity = target.body.velocity + toward * pull;
|
target.body.velocity = target.body.velocity + toward * pull;
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < (int)sim.world.dummies.size(); i++)
|
||||||
|
{
|
||||||
|
Dummy& dummy = sim.world.dummies[i];
|
||||||
|
Vec2 center = {dummy.box.x + dummy.box.w / 2, dummy.box.y + dummy.box.h / 2};
|
||||||
|
if (dummy.tile >= 0 || !is_target(sim, MAX_FIGHTERS + i, attack.owner) || !is_in_cone(attack, center))
|
||||||
|
continue;
|
||||||
|
Vec2 toward = vec2_normalize(attack.position - center);
|
||||||
|
dummy.wobbleSpeed += toward.x * VACUUM_PULL_RATE * fighter.stat_get(STAT_KNOCKBACK) * WOBBLE_PER_PULL * TICK;
|
||||||
|
}
|
||||||
// Each interval (the hit cooldown counting it down), everyone in the cone can be nibbled again.
|
// Each interval (the hit cooldown counting it down), everyone in the cone can be nibbled again.
|
||||||
float interval = fighter.level_get(attack.key).cooldown / fighter.stat_get(STAT_ATTACK_RATE);
|
float interval = fighter.level_get(attack.key).cooldown / fighter.stat_get(STAT_ATTACK_RATE);
|
||||||
bool isPulse = attack.hitCooldown <= 0;
|
bool isPulse = attack.hitCooldown <= 0;
|
||||||
@@ -2323,13 +2350,16 @@ void Weapons::gust_move(Sim& sim, Attack& attack)
|
|||||||
if (!is_target(sim, target, attack.owner) || !is_in_cone(attack, center))
|
if (!is_target(sim, target, attack.owner) || !is_in_cone(attack, center))
|
||||||
continue;
|
continue;
|
||||||
attack_hit(sim, attack, target, center);
|
attack_hit(sim, attack, target, center);
|
||||||
if (target >= MAX_FIGHTERS)
|
|
||||||
continue;
|
|
||||||
// Boxing Glove adds to it as to any knock.
|
// Boxing Glove adds to it as to any knock.
|
||||||
|
Vec2 push = vec2_normalize(center - attack.position) * attack.stats.speed * cone_strength_get(attack, center) *
|
||||||
|
sim.fighters[attack.owner].stat_get(STAT_KNOCKBACK);
|
||||||
|
if (target >= MAX_FIGHTERS)
|
||||||
|
{
|
||||||
|
dummy_push(sim.world.dummies[target - MAX_FIGHTERS], push);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Fighter& fighter = sim.fighters[target];
|
Fighter& fighter = sim.fighters[target];
|
||||||
float strength = attack.stats.speed * cone_strength_get(attack, center) *
|
fighter.knock_take(push * fighter.stat_get(STAT_KNOCKBACK_TAKEN), attack.owner);
|
||||||
fighter.stat_get(STAT_KNOCKBACK_TAKEN) * sim.fighters[attack.owner].stat_get(STAT_KNOCKBACK);
|
|
||||||
fighter.knock_take(vec2_normalize(center - attack.position) * strength, attack.owner);
|
|
||||||
}
|
}
|
||||||
shots_drift(sim, attack, attack.stats.speed * GUST_SHOT_SHARE, 0, attack.isCopy ? 0 : GUST_RESTORE);
|
shots_drift(sim, attack, attack.stats.speed * GUST_SHOT_SHARE, 0, attack.isCopy ? 0 : GUST_RESTORE);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user