I’ve just released Rez v1.9.11.
I’m actually making pretty good progress with my demo game Age of Ruin and all of the changes to Rez lately have been made in support of building that game.
Release notes:
- Updated to Alpine.JS v3.15.12
- Only copy standard assets (Alpine.JS, Bulma.CSS, …) if they are referenced using an @asset tag
- Automatically populate the
owner_id of @inventory elements at runtime
- RezDecision gains an
owner property
- Safety updates to the RezInventory API
- Pass a copy-customer inline function using the ^copy initializer
- RezDieRoll gains max property
- RezInventory passes slot_id and slot_binding correctly to on_insert/on_remove functions
- RezEvent.modal supports an animation delay
- Removing items from @inventory now fires the right events with the right params
- @System’s can now observe life-cycle events such as card_will_start, scene_did_end, etc…
- Adds Map#buckets() to the JS stdlib
- RezBasicObject#addCopy() uses param passing style and supports a post-init-fn for in-line customisation of copies
- RezScene provides resume_event as a way to handle more complex scene resume scenarios
RezInventory is now working really well and seems fairly intuitive to use (to me at least). For example:
@item it_arm_leather_cuirass {
type: :armour
label: "leather cuirass"
value: 25
weight: 8.0
material: :leather
quality: :ordinary
active_slot_id: #armour_slot
modifiers: [
spd: -1
dex: -1
dr: 3
]
}
When this item is placed in a player (or NPC) armour slot it will automatically modify their SPD, DEX, and DR stats. When it is removed, the stats modifications will be reversed. To make that work I just added an on_insert and on_remove handler to the built in @item, e.g.
on_insert: +(item, {slot_id, owner}) => {
if(slot_id === item.active_slot_id) {
item.apply_modifiers(owner);
}
}
It’s pretty slick.
Now that @system can respond to life-cycle events I was able to build a threat system that responds to player actions:
@system threat_system {
...
after_lifecycle_event: (system, event_name, params, _result) => {
if(event_name === "card_will_start") {
const card = $(params.card_id);
if(card && card.kindOf("location")) {
system.note_move(card);
}
} else if(event_name === "scene_did_end") {
if($game.current_scene && $game.current_scene.id === "sc_battle") {
system.note_combat($player.location);
}
}
}
...
}
I’m using this to drive NPC response to player actions.
Passing copy customisers lets me move things closer to where the copy is made:
dr_id:^copy:#T_stat{
copy.base = 0;
}
This creates a copy of the T_stat element and then runs the function binding copy to the new object. A small change but very handy.
The new resume_event for RezScene allows for much more flexible response to a scene being resumed without digging into the guts of the event processor. It’s hard to show a concise example but it allows the scene to, for example, play a card after resuming. This is important in the game because using the inventory in combat costs an action and might result in an NPC, rather than the player, getting the next action. That requires triggering an event on resuming from the inventory scene, during a fight.
Also nothing to do with this release but I am beginning to make real use of Rez’s behaviour trees for NPC behaviour. For example a behaviour template for taunting an NPC:
@behaviour_template behaviour_taunted ^[$sequence [cond_taunted]
[$select
[$sequence [cond_in_weapon_range] [act_melee_attack]]
[act_advance]]]
If the NPC is in its weapon range it will make a melee attack, otherwise it will advance toward the player. I’m building up libraries of increasingly complex behaviours for NPCs.
I’ve given up thinking I will be “done” enhancing Rez because as my game pushes its limits I find ways to improve it.