Profile stats, first-run hints, tiered balance, a wave-driven whip, and more options
- Profile Stats: damage dealt, kills and wins (single player and multiplayer) and the most and least played weapons and trinkets, counted from running totals in the simulation so online rewinds correct them. Protocol 6. - First-run control hints in the sandbox (and Chat in lobbies), each gone for good once used. - The ready countdown and a timed round's last five seconds beep (new countdown sound), and those seconds show big. When time runs out, everyone short of the most health dies. - Weapon balance tuned into tiers: Whip and Grenade Launcher on top, then melee, ranged, and utility (Vacuum, Grapple, Uzi) at the bottom. - The whip's lash is a chain of links a wave rolls down: windup, loop, crack, then a floppy recoil. - Muzzles come from Muzzle nulls in weapons.anm2 (read in at build time), for shots and the flash, which now follows the weapon. - Settings: Quit, Scale (1x-4x or Free), FPS meter and limit beside Vsync, Mute on Unfocus, Damage Numbers, Rumble, Stick Deadzone, and an Online section (Host, Chat, Ping) shared with the Multiplayer page. - The menu header lays out tabs and buttons by their names. About is sandbox-only. The score no longer shifts with the menu's tab. - Smaller meters, 90 tips (all ending in !), and a shorter lobby welcome.
This commit is contained in:
1 parent
e9d8cac926
commit
b96defa1e6
32 files changed
+1368
-396
No files matched your search
+60
-12
@@ -6,6 +6,11 @@
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
// Rumble: the damage taken that shakes a gamepad fully, and how long, and the lighter tick for landing a hit.
|
||||
constexpr float RUMBLE_FULL_DAMAGE = 60;
|
||||
constexpr Uint32 RUMBLE_HIT_TIME = 180;
|
||||
constexpr float RUMBLE_LANDED = 0.15f;
|
||||
constexpr Uint32 RUMBLE_LANDED_TIME = 60;
|
||||
constexpr int BLINK_MILLISECONDS = 80;
|
||||
|
||||
// How long a claimed shot takes to turn from its old owner's colour to its new one's.
|
||||
@@ -97,6 +102,7 @@ constexpr float TELEPORT_RING_ALPHA = 0.35f;
|
||||
constexpr float WHIP_INNER = 2;
|
||||
constexpr float WHIP_JITTER = 0.5f;
|
||||
constexpr float WHIP_OUTER = 5;
|
||||
constexpr float WHIP_TAPER = 0.35f;
|
||||
constexpr float WISP_FRAME_STAGGER = 0.3f;
|
||||
constexpr int TOMATO_BLOBS = 6;
|
||||
constexpr float TOMATO_BLOB_MAX = 3.5f;
|
||||
@@ -167,6 +173,8 @@ struct Stroke
|
||||
float outer = 0;
|
||||
float inner = 0;
|
||||
float jitter = 0;
|
||||
// Its width at the end, as a share of its width at the start.
|
||||
float taper = 1;
|
||||
};
|
||||
|
||||
// A beam, rope or whip, each piece coloured by the strength there, dimming along it the way damage falls off. Jitter
|
||||
@@ -205,10 +213,12 @@ static void strength_line_draw(Game& game, Attack& attack, Stroke stroke)
|
||||
for (size_t i = 0; i + 1 < points.size(); i++)
|
||||
{
|
||||
float strength = base * falloff_at(distances[i] / reach);
|
||||
float width = math_lerp(1, stroke.taper, distances[i] / distance);
|
||||
if (layer == 0)
|
||||
game.renderer.line_draw(points[i], points[i + 1], stroke.outer, color_dim(color, strength));
|
||||
game.renderer.line_draw(points[i], points[i + 1], stroke.outer * width, color_dim(color, strength));
|
||||
else
|
||||
game.renderer.line_draw(points[i], points[i + 1], stroke.inner, color_shade(color, fill_get(strength)));
|
||||
game.renderer.line_draw(points[i], points[i + 1], stroke.inner * width,
|
||||
color_shade(color, fill_get(strength)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,10 +452,18 @@ void Scene::shake_add(float amount)
|
||||
game.effects.shake_add(amount);
|
||||
}
|
||||
|
||||
void Scene::flash_spawn(Vec2 position, float angle, float size, int owner)
|
||||
// A shot's muzzle flash, which keeps to the muzzle of the weapon that fired it (see flash_follow).
|
||||
void Scene::flash_spawn(Attack& attack, float size)
|
||||
{
|
||||
if (!isMuted)
|
||||
game.effects.flash_spawn(position, angle, size, game.color_get(owner));
|
||||
if (isMuted)
|
||||
return;
|
||||
game.effects.flash_spawn({.color = game.color_get(attack.owner),
|
||||
.position = muzzle_get(attack),
|
||||
.angle = attack.angle,
|
||||
.size = size,
|
||||
.owner = attack.owner,
|
||||
.hand = attack.hand,
|
||||
.weapon = attack.weapon});
|
||||
}
|
||||
|
||||
void Scene::fighter_afterimage_spawn(Fighter& fighter)
|
||||
@@ -477,12 +495,22 @@ void Scene::attack_aura_spawn(Attack& attack)
|
||||
tint_get(game, attack));
|
||||
}
|
||||
|
||||
// A hit's number (unless they're turned off) and its share of the DPS meter, and with rumble on, a shake of this
|
||||
// screen's gamepad: harder for more damage taken, and a light tick for a hit landed.
|
||||
void Scene::number_spawn(Damage& damage)
|
||||
{
|
||||
if (isMuted)
|
||||
return;
|
||||
game.effects.number_spawn(damage.point, damage.amount, damage.target, game.color_get(damage.owner));
|
||||
if (game.settings.isDamageShown)
|
||||
game.effects.number_spawn(damage.point, damage.amount, damage.target, game.color_get(damage.owner));
|
||||
game.effects.dps_record(damage.amount);
|
||||
if (!game.settings.isRumbling)
|
||||
return;
|
||||
int device = game.devices[game.local];
|
||||
if (damage.target == game.local)
|
||||
game.input.rumble_play(device, damage.amount / RUMBLE_FULL_DAMAGE, RUMBLE_HIT_TIME);
|
||||
else if (damage.owner == game.local)
|
||||
game.input.rumble_play(device, RUMBLE_LANDED, RUMBLE_LANDED_TIME);
|
||||
}
|
||||
|
||||
// A level going up or down chimes, and outside the menu pops up over this screen's fighter.
|
||||
@@ -880,17 +908,18 @@ void Scene::attacks_draw()
|
||||
}
|
||||
else if (kind == ATTACK_WHIP)
|
||||
{
|
||||
// A plain lash keeps its full width while it unfurls, then thins away after the crack. The tip sprite
|
||||
// rides the end of the whip, pointing the way it runs.
|
||||
// A plain lash keeps its full width while it unfurls, then thins away after the crack, slowly at first. It
|
||||
// tapers toward its tip. The tip sprite rides the end of the whip, pointing the way it runs.
|
||||
Vec2 shake = jitter_get(fill_get(strength_get(attack, attack.tip)));
|
||||
float fade = attack.is_charged() ? progress : std::max(0.0f, (progress - PATH_OUT) / (1 - PATH_OUT));
|
||||
float width = (1 - fade) * attack.scale;
|
||||
float width = (1 - (attack.is_charged() ? fade : fade * fade)) * attack.scale;
|
||||
std::vector<Vec2> points =
|
||||
attack.is_charged() ? std::vector<Vec2>{attack.position, attack.tip} : lash_get(attack);
|
||||
Vec2 end = points.back();
|
||||
Vec2 before = points[points.size() - 2];
|
||||
strength_line_draw(game, attack,
|
||||
{points, WHIP_OUTER * width, WHIP_INNER * width, attack.is_charged() ? 0 : WHIP_JITTER});
|
||||
{points, WHIP_OUTER * width, WHIP_INNER * width, attack.is_charged() ? 0 : WHIP_JITTER,
|
||||
attack.is_charged() ? 1 : WHIP_TAPER});
|
||||
game.sprites.effects.draw(renderer, "Whip Tip", 0,
|
||||
{.color = color_fade(tint, 1 - fade),
|
||||
.position = end + shake,
|
||||
@@ -1205,6 +1234,26 @@ void Scene::held_draw(Fighter& fighter)
|
||||
hand_draw(fighter, held, 0, draw);
|
||||
}
|
||||
|
||||
// Keeps a muzzle flash on the muzzle of the weapon that fired it as that weapon moves after, as it's drawn (the main
|
||||
// hand's kicking back with its recoil). Once the fighter is gone or that hand holds something else, it stays put.
|
||||
void Scene::flash_follow(Flash& flash)
|
||||
{
|
||||
if (flash.owner >= game.sim.fighterCount)
|
||||
return;
|
||||
Fighter& fighter = game.sim.fighters[flash.owner];
|
||||
int slot = fighter.hand_slot_get(flash.hand);
|
||||
if (!fighter.isAlive || slot < 0 || fighter.weaponLoadout[slot] != flash.weapon)
|
||||
return;
|
||||
float side = fighter.is_left() ? -1 : 1;
|
||||
float kick = flash.hand == 0 ? kick_get(fighter) * side : 0;
|
||||
Attack probe = {.origin = fighter.hand_get(flash.hand),
|
||||
.angle = vec2_angle(fighter.aim) + kick,
|
||||
.weapon = flash.weapon,
|
||||
.isLeft = fighter.is_left()};
|
||||
flash.position = muzzle_get(probe);
|
||||
flash.angle = probe.angle;
|
||||
}
|
||||
|
||||
// Dual Wield: the off-hand weapons, a darker shade of the fighter's colour, fanned out behind it (see
|
||||
// Fighter::hand_get), the furthest back first so the nearer cover them. Each shakes and reloads like the main one.
|
||||
void Scene::offhand_draw(Fighter& fighter)
|
||||
@@ -1244,8 +1293,7 @@ void Scene::hand_draw(Fighter& fighter, int weaponSlot, int hand, Draw draw)
|
||||
float frame = SDL_GetTicks() * art.fps / SDL_MS_PER_SECOND;
|
||||
if (tether)
|
||||
{
|
||||
Vec2 end = tether->def()->kind == ATTACK_WHIP ? tether->tip : tether->position;
|
||||
draw.angle = vec2_angle(end - draw.position);
|
||||
draw.angle = vec2_angle(tether->position - draw.position);
|
||||
animation += " Base";
|
||||
}
|
||||
else if (charge)
|
||||
|
||||
Reference in new issue
Block a user