Ricochet Ritualwiki

Systems

The machinery underneath: how damage resolves, how score is earned, how the audio tracks a run, and how these pages are generated.

Combat

Two damage entry points

takeDamage is the one every weapon uses: it respects invulnerability frames, shields, mitigation and the shield enemy's guard arc, and it returns whether the hit landed. takeDamageRaw skips all of it and is for damage-over-time ticks that have already been gated elsewhere. Anything that rewards you for hitting — life steal, combo, on-hit procs — has to check the return value, or it pays out on hits that were refused.

Invulnerability frames are shared

An enemy that has just been hit ignores further hits for a moment. This is what stops a multi-hit effect from deleting a boss in one frame, and it is also why an orb passing through a crowd does not double-dip on the enemy it is touching.

Every status ticks in one place

Burn, bleed, freeze, chill, stun, curse and root all tick in a single function on the base enemy, so every status a card applies is guaranteed to run.

Telegraphs match their hitboxes

Ground circles are drawn flattened for perspective, and every one is drawn at the radius its damage actually uses, so a boss slam or a meteor never hits outside the circle it drew.

Enemies go round trees by how much room there is

Everything rests on one number, clearance: how far a point is from the nearest solid box.

Routes are planned for each body size. One distance-to-you map per size of body on the field, over a 32px grid round you, where a cell is open only if a body that size fits there and costs more the tighter it is. So a Brute is never sent at a gap only a Mushroom fits through: it goes round. If you are somewhere it cannot reach at all, it waits in open ground until you come out, rather than wedging itself in the mouth of the gap and corking it for everything behind. A step between two cells only counts if the straight line between them has room all the way along, so the front of a queue never backs in and out of a gap it cannot take.

Steering keeps its distance. Every frame the body scores the headings round the one it wants by how well they point and how much room they leave, so it swings wide of a trunk early instead of meeting it and sliding.

Bodies are tested at their feet against the real obstacle boxes, not at the sprite origin (which sits on the creature's head). Knockback and the drag of a Black Hole, Singularity or Gravity Snap go through the same collision, so nothing is thrown through a tree either.

The horde keeps its shape. Bodies ease apart rather than stacking, bigger ones shouldering smaller ones aside, so a crowd forms a ring round you instead of a single pile an orb could clear in one strike. Anything dashing is exempt, anything frozen or holding you stands firm, and whatever a crowd-control card is dragging is left to be piled up. Enemies arrive from just outside the camera's view — the real view, which stops at the map's edge — and one left far out of sight for a few seconds is brought back to just off screen ahead of you. Bosses are never moved. Once the wave has nothing left to send and three or fewer remain, arrows at the screen edge point to them.

An orb that gets stuck lets itself out

Two obstacles with a narrow gap between them can hold a thrown orb indefinitely, because nothing damps a wall bounce enough to end it. So the orb frees itself: if it has not travelled more than a short distance for about a second and a half, it checks whether it is in a pocket, and phases out through the scenery if it is.

Confinement is what marks a pocket, not speed, since a slow trapped orb comes to rest inside the gap. It samples a ring round the orb: a flat wall the orb has rolled up against blocks at most half of it and is reachable on foot; a gap or an inside corner blocks more. An orb already at rest is nudged toward you as well, since phasing alone does nothing for something with no momentum.

Recall does not phase. A recalled orb comes home round the scenery, bouncing and sliding off it, and if a tree catches it you can step aside, since the pull comes from wherever you stand. A pull that cannot arrive gives up after five seconds and the orb flies on at the speed the pull gave it. The escape above stands down while the orb is being recalled.

Hits land with weight, not lag

Each hit on an enemy freezes the game for a few hundredths of a second. Every freeze adds heat that drains over time and scales the next one down: a lone hit, or hits a second or more apart, get the full freeze; a rally goes 0.12, 0.06, 0.03, 0.01s and then nothing, and the punch comes back after a short breather. Screen shake fades the same way under rapid hits. Hitting a tree freezes and shakes nothing.

Damage numbers

Bigger hits climb a colour ladder: white under 20, yellow 20+, orange 50+, red 100+, magenta 200+, purple 350+, cyan 500+, blue 700+, gold 1,000+, white-hot with a red glow from 1,500, and cycling through the rainbow from 2,000. Each step is also drawn a little larger. Crits add a "!". Burn ticks, heals and damage you take keep their own fixed colours.

The combo ladder

Consecutive hits inside a window. Several cards scale off it, and the audio tracks it — every kill fires a confirm pitched to your current tier, so the sound of a run climbing is information rather than decoration.

TierAt
COMBO×1where every combo starts — nothing is promoted into it
NICE×5promotes here: a banner, and the next rung of the streak
SLICK×12promotes here: a banner, and the next rung of the streak
WICKED×25promotes here: a banner, and the next rung of the streak
SAVAGE×45promotes here: a banner, and the next rung of the streak
RUTHLESS×75promotes here: a banner, and the next rung of the streak
BRUTAL×120promotes here: a banner, and the next rung of the streak
UNREAL×190promotes here: a banner, and the next rung of the streak
LEGENDARY×300promotes here: a banner, and the next rung of the streak
GODLIKE×500promotes here: a banner, and the next rung of the streak

Score

Score comes from kills, weighted by what died and multiplied by the wave's modifier and composition, plus a survival term. An elite is worth more than the trash it spawned among; a boss is worth more again. Records persist between runs, and the difficulty a run was played on is recorded with it — a HARD score and an EASY score are not the same number and are not stored as though they were.

Sound

What a kill sounds like. Every orb kill fires a short confirm pitched to your current combo tier, several voices deep and rate-limited — short enough that a double kill is two sounds, long enough that an effect wiping eight bodies on one frame is not eight. Dropping the combo fires the only sound in the set that falls in pitch.

Crossing a tier fires the next rung of the streak ladder, built the way a Valorant kill streak is: one instrument, and every rung a clear step higher and a little bigger than the one before. Each is a quick run up to its note, from C5 at the first tier to C7 at the last, and the last one is an event of its own, with a chord that blooms underneath and sparkle off the top. There are six rungs and ten tiers: the first five promotions climb the first five rungs, BRUTAL, UNREAL and LEGENDARY replay the fifth pitched up to G6, A6 and B6 so the climb keeps rising, and GODLIKE keeps the last rung to itself.

Voices and rate limits are central, not per-caller. A pool of sources per sound key lets one overlap itself where that overlap is the feedback, and pins announcements to exactly one, since two wave-clears at once is always a mistake. Minimum spacing is enforced in one place, because the callers that get this wrong are exactly the ones that never think about audio — a per-frame branch in an enemy update, a damage tick in a crowd.

Sounds are placed where they happen — against the middle of the camera's view, with a gentle fade: full volume anywhere on screen, easing to about a third a screen or so beyond it, and a soft pan that never puts a sound hard in one ear. Your own orb's sounds keep a floor, so your weapon connecting is always audible. Every effect is made mono when it loads so this applies to all of them.

Nearly every sound in the game is synthesised by a Lua script in the repo rather than licensed, which is why they sit together tonally — including a voice of its own for every card that fires an effect: Void Pulse, Crescendo, Death Nova, Thunderclap, Volatile Core, Rupture, Aegis's parry, the Owl's strike and Slingshot's arming click. One bought sound was kept: the orb recall.

How this wiki is built

Two commands, run from this site's own repository against a checkout of the game. tools/dump_main.lua runs under LÖVE, loads the game's own modules, and writes every definition table to JSON — including the ones that are file-local and therefore invisible to an ordinary dumper. Those are recovered through debug.getupvalue, which is how unlock waves, spawn weights, stack caps and prerequisites reach this site without anyone retyping them.

tools/build.mjs then renders docs/ from that JSON plus the hand-written prose in content.mjs. The split is the point: if a fact could have been derived and was typed instead, it is a bug waiting to drift.

Enemy portraits are not copied out of the sprite folder. 16 of the 23 types borrow another one's art, so tools/portraits_main.lua renders each frame through the same recolour shader the game uses at draw time — a hue rotation in YIQ, or a multiply tint for the sprites with no chroma to rotate. Copying the PNGs would produce a bestiary in which a third of the roster is the same picture repeated.