Boons
Offer a choice of boons with rolled rarities, let the player pick one, and plug it into combat as data: damage multipliers, on-hit statuses and chain bolts, dash blasts, health, dash charges, cooldowns and speed.
Run upgrades granted by gods (upgrades.boons) #
What it is for #
upgrades.boons gives a run its upgrades. When a reward is collected, a script asks for it, or your code calls offer, the kit draws a few eligible boons, rolls the rarity of each, pauses the game and waits for the player to choose. The chosen boon then acts on combat as data: damage multipliers, a status or a chain bolt on hit, a blast at a dash, health, dash charges, cooldowns, speed. A boon is data in two collections (gods and boons); the kit leaves the choice screen to your interface, which reads boons.offer and calls choose. With no documents in the project, the kit plays a built-in set of five gods and their boons.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "upgrades.boons" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "upgrades.boons",
config: { "choices": 3, "rarity": { "common": 60, "rare": 30, "epic": 10 } } }
The kit needs combat.damage, combat.status, combat.health and game.engine.
First example #
<!-- test: kits/game_engine/host/tests/upgrades_boons.rs::an_offer_pauses_and_a_choice_resumes_and_acquires --> With two gods' boons in the project, offer draws from the eligible ones (a boon whose requires is not owned is left out), pauses the game, names the offer offer:1 and keeps answering the same offer until it is settled. choose(0) takes the first choice, resumes the game and sets boons.count to 1.
{ "op": "call", "service": "boons.offer", "method": "offer", "args": [{ "source": "altar" }] }
{ "op": "call", "service": "boons.offer", "method": "choose", "args": [0] }
Events, in order: boon.offered, then boon.acquired. A wrong index answers false and the offer keeps waiting.
Settings and defaults #
| Setting | Type | Default | Meaning |
|---|---|---|---|
choices | integer | 3 | boons per offer (1 to 4) |
rarity | object | { common: 70, rare: 25, epic: 5 } | weights of a rarity roll (0 to 100 each; all zero means common) |
pauseOnOffer | boolean | true | pause the game while an offer waits; choose resumes it |
gods | list | [] | restrict offers to these gods; empty = every god |
Content: gods and boons #
A god is { id, name, title?, color } (color is #rrggbb). A boon is { id, god, name, description, slot?, requires?, effects[], rarityScale? }:
slotisattack,special,dashorpassive. Acquiring a boon removes the one you own in the same slot (not for a passive).requireslists boon ids that must be owned for this boon to be offered.rarityScaleis{ common, rare, epic }, the multiplier of the effects at each rarity (defaults 1, 1.3 and 1.6).effectshold at least one of:damage_mult(on,value),incoming_mult(value),on_hit_status(on,status,stacks,chance),on_hit_bolt(on,damage,radius,targets,chance),dash_blast(damage,radius,status,knockback,at),dash_invulnerable(seconds),max_health(amount),heal(amount),dash_charges(amount),special_cooldown_mult(value),move_speed_mult(value). The triggeronisattack,special,dashorany.
{ "id": "zeus_storm_edge", "god": "zeus", "name": "Storm Edge", "description": "Your attacks arc lightning to a nearby foe.",
"slot": "attack", "effects": [{ "type": "on_hit_bolt", "on": "attack", "damage": 12, "radius": 5, "targets": 1 }] }
Services, events, variables #
boons.offer(service):offer({ god?, count?, source? })(answers the offer{ id, god, source, choices[] }, ornullif nothing is eligible or a hook cancelled it),current(),choose(index)(answers whether it worked),grant(id, rarity?),owned(),gods(),boons(). A choice is{ boon, god, name, description, rarity, rank, replaces? }.boon.offered(event):{ offer, god, choices, source }.boon.acquired(event):{ boon, god, rarity, rank, replaced? }.boon.proc(event): an extra hit fired,{ boon, effect, from, at, targets }(on_hit_boltordash_blast).- Variables:
boons.offer(the waiting offer, null when none),boons.ownedandboons.count(how many boons are owned). - Verbs for content:
offer_boon { god?, count? }andgrant_boon { boon, rarity? }(actions),has_boon { boon }(condition). - Listens to:
reward.collected(a reward of typeboon, with an optionalgod, starts an offer),combat.damaged,dash.started,dash.ended.
The random draw uses its own fork per offer (offer:<n>), and the offer counter is saved, so a seed gives the same offers.
Hooks and modding #
- Hook
boon.offer: payload{ god, count, source },godandcountmutable, cancellable. A cancelled offer draws nothing:offeranswersnull, no event, no pause. - Hook
boon.acquire: payload{ boon, god, slot, rarity, replaced, via }(viaischooseorgrant),raritymutable (it sets the scale of the effects), cancellable (chooseandgrantanswerfalse, the offer keeps waiting). - Hook
boon.proc: payload{ boon, god, effect, target, amount, radius }witheffecton_hit_status,on_hit_boltordash_blast;amountandradiusmutable, cancellable. It is asked after the chance was rolled. - A mod may change
choices,rarity,pauseOnOffer,godsand the collectionsgodsandboons.
The damage multipliers of a boon are taps of the combat.damage hook, ordered with yours by priority.
Engines #
The rules are the same Rust implementation on the web, the native player, Godot, Unity and Unreal; effects act through the combat kits of the game. The web player draws the lightning of a bolt or blast on boon.proc as an additive ribbon from the origin to each target.
When it does not do what you expect #
offeranswersnull: no boon is eligible (all owned, a missingrequires, agodsrestriction), or aboon.offertap cancelled it.- The game stays paused: an offer waits; call
choose, or setpauseOnOffertofalse. chooseanswersfalse: no offer waits, the index is out of range, the boon is already owned or aboon.acquiretap cancelled it.- A boon never appears: its
godis not in thegodsdocument, or itsrequiresboon is not owned yet.
Limits #
The kit has no choice screen: your interface reads boons.offer. A boon from the same slot replaces the previous one; there is no upgrade of a boon beyond its rank 1.
Versions #
Kit 1.3.0 (hooks boon.offer, boon.acquire, boon.proc; collections moddable). Service boons.offer 1.0.0.