Take your Balor to work day

While implementing the Balor I thought I might take notes on what goes into implementing a frame in LT. For reference, here are all the stats and abilities for the Balor we need to implement:

Balor stablock

  • First step is to make frame resource. This is a Godot data container that pulls in everything that makes up a mech frame.
    • Add in the Balor sprite by Blobertson. We love these tokens but they just ended up being the wrong resolution for LT, but I’m happy to use them until Gen makes a new one.
    • Fill out dropdowns & standard inputs for mount types and statblocks

Godot Resource for the Balor mech frame

Scouring Swarm

Scouring swarm textbox

  • This will be “mt_scouring_swarm”. I’m using the naming scheme that the COMP/CON lcps established: a prefix for resource type + the lowercase name of the resource.
    • mt == “mech trait” (can show some others… had to make some up for things that comp/con doesn’t address)
  • All traits/systems/weapons start with a “kit” that encapsulates the entire ability, listing all actions, passives, SP cost, and charges.
  • To the mt_scouring_swarm kit, we’ll add one basic reaction – doesn’t spend a reaction point, but uses the same system as normal reactions.
    • Uses the “ActionReactionOnComingWithin” archtype. made a number of these that handle common patterns of when things trigger.
    • This one, ironically, only triggers on characters’ turn starts, not when they first come within a distance. handled by checkboxes.
    • The core of the reaction system is keying off of one of an array of defined event signals — we just need “NEW TURN”. If the ability was “when a character comes within 2 spaces or when they start their turn there”, we’d need to have this reaction also listen to “MOVE” (in addition to checking the archtype’s box)

Scouring swarm resource

  • With the trigger handled entirely by the archtype (I think we can totally ignore the bit in the text about being grappled – anybody grappled is going to be within 1 space, by definition!), we need to make a new script for the effect.
    • Extends the archtype, inheriting all the trigger-handling in the base script, but overriding the “activation” function where the meat of the effect lives.

Scouring swarm script

  • We have a choice here – we could implement it RAW where the damage is optional or simplify things by making it automatic against only hostiles. Usually this is the call I’d make, but honestly I think we can let it be automatic. The only scenario I think you wouldn’t want to do damage is, like, grappling a berserker and wanting to avoid triggering its aggression. I don’t think that one scenario justifies the prompt spam for every other time the balor will want to do damage. I’ll let it be automatic against enemies here & if a reason comes out in playtesting to add a confirm prompt, we can do that later
    • So the only thing scouring swarm’s activation has to do is queue up a “do 2 kinetic damage” event against the triggering unit
    • The way events pass information around is via “context” objects which have a specified number of slots that are named & typed. The Damage event expects a unit, a number, and a damage type. It can also take some flags (eg “AP”, “cannot be reduced”, or “self-inflicted”) and a source unit (so things reacting to the damage event can inspect it and say, for example, “that unit is more than 3 spaces away — I get reduction”. The only two unit slots we have in Context objects are “unit” and “target_unit” so we have to use the latter for the source unit. If I was redesigning this from scratch I’d have probably used “target_unit” for the unit getting damaged and “unit” for the source, but swapping those around at this point would be a big chore with no direct gain.
  • We’ve already imported all of the rules text into a big google sheet, which gets turned into a .csv file that the game uses for tooltips and descriptions. With all the keys matched up between the files and the COMP/CON IDs, we don’t actually have to do ANY extra work by default to have the right text show up.

And that’s all we have to do for scouring swarm! If it were more complicated or doing something novel, I might write an automated test for it to make sure it both works and will never break, but this was simple enough that I’m going to just mark it as “test ingame” on the content sheet.

Regeneration

Regeneration textbox

  • Same as last time, this’ll be a reaction — the balor reacts to the end of its own turn and queues up a heal-damage event instead of a damage event.
  • Since it’s so simple, let’s take a closer look at this one’s archtype: “ActionReactionSelf”

Action reaction self script

  • Two main functions: one to say what context properties are required, such as the damage event’s unit/amount/type, and a function that processes the context to see if it’s something this particular ability should react to.
  • For ActionReactionSelf, all it cares about is if the character in the “unit” property is the same character as the one holding the kit/gear that has this reaction. With a reaction trigger set to “on the end of a unit’s turn”, this comes out to meaning “on the end of a unit’s turn, and that unit is the one with this gear”.
  • So all we have to do for Regeneration is override the activate() function and have it give us a little bit of healing when it triggers.

Regeneration script

Self-Perpetuating

Self perpetuating textbox

  • This one is a bit odd. It doesn’t directly interact with anything on the battlefield. The rest/repair system exists entirely outside of the reaction system, so we don’t have a predefined way to hook into it. For the Everest’s repair discount, I had the repair screen specifically check for if the mech has the Replaceable Parts trait. I don’t like specific checks like that generally since it makes things less modular. Much better to define a flag on a mech that anything that cares about it can toggle on or off — but since these really are one-off abilities, I’m more willing to make exceptions.
  • One idea I have that could potentially avoid this is by making a reaction for the end of combat; we simply return the Balor to full health when the fight ends. Two potential problems with this:
    • We’d want to avoid any healing / repair fx playing awkwardly right there at the end, so would need to create a “SKIP_FX” flag for the heal event.
    • Does resting actually also repair the Balor if it’s destroyed? I’m not sure — time to do a quick consultation of the archives (searching the PilotNET rules channel)
    • No mention of it, actually. Just some questions about whether it also repairs structure. So I assume it does not interact with being destroyed; players will still have to spend their 4 repairs to get it back on its feet.
  • Let’s just do the “heal at the end of combat” thing with a flag to skip any fx. It’ll be less special-case-y.
  • Actually, now that I say that, I realize it’s no good — if the Balor is Exiled at the end of combat (e.g. Fold Space), it can’t use even implicit reactions like this, so would miss the trigger to get healed.
  • Actually, now that I say that, there is already one other place that I have game abilities doing something on all rests: I’m resetting certain dice! (gunslinger, brawler, and stormbringer). How am I doing that?
    • Oh :: I just reset the dice on character spawn. That’s no good for us, since we want to be at full HP between scenes.
  • Special casing in the Repair screen, it is. Time to exit Kit & resource land and enter the UI side of the game…. I don’t want to think about this too hard. Let’s take a page out of the everest’s book and just give a full discount to repairing HP instead of figuring out how to make it happen automatically. We can add that little cherry on top in a later polish pass. I’ll add a to-do note in the content sheet.

Self perpetuating discount code

Hellswarm

Hellswarm text box

  • Core powers have the same structure as traits: we have a trait called “cp_hellswarm” and it has some actions on it.
  • This time it’s a player-initiatable action instead of a reaction. To do persistent effects, I have an object type I can apply to units called a “Buff”. Buffs can react like normal actions can (though they can’t spend Reactions by default) and are how I grant passive effects like additional accuracy or range.

List of all buffs in the game so far

  • To grant a Buff, I have an action archtype called ActionSystemApplyBuff. Let’s make one of those, and change its values to be a protocol, consume CP on use, and apply the buff we give it to the character that uses this action (as opposed to some distant target).
  • Let’s make a buff for this hive frenzy that applies to the unit and sticks around for the rest of the battle. We can have it apply Shredded for as long as it’s applied.
  • For the Structured effect, we can go through more or less by the same process as the frame traits. We respond to the “structured” event, execute before the structure applies, and abort it if we roll a 6. (we can actually copy Custom Paint Job more or less verbatim)
    • For “gains immunity to all damage until the end of the current turn”, we’ll apply a second damage immunity buff that’s set to expire appropriately.
    • No custom script needed; we already have the passive TO for damage immunity from the Insulated trait (immune to burn damage).
    • We WILL need to add it to the localization sheet if we want it visible. May as well.
    • I’m going to go tweak Custom Paint Job’s priority to make sure that its effect gets queued after this one. I have a shared priority class that anything can reach into and use that replaced the previous system where everything just used magic numbers on their own. This was technically more modular but obviously when you’re making a system that coordinates the order of disparate things, you’re gonna have a hard time if all the information is also disparate.

Hive frenzy script

  • For the “more damage and more healing” effects, we’re going to have to go into those abilities and have them change their numbers based on if we have the popped-CP buff. I don’t like referencing stuff from other kits directly, but when the ability is specifically called out in the rules text, there’s not really any getting around it.
  • Finally, the soft cover to self and allies: if it was just to self, we could throw it on the base hive frenzy buff, but it needs to apply to adjacent allies as well. Fortunately, we have one more archtype for this: a reaction that adds or removes a specified buff when units come into or go out of a specified range: ActionReactionAura. We’ll set that up as a separate action on the cp kit, and have it only run when we have the hive frenzy buff.

  • Finishing up: we add all these actions to the Hiveswarm kit. I usually forget this step, so chalk one up to making fewer mistakes when you’re writing a log.

Swarm Hive Nanites

  • And I want to show off at least one weapon, so let’s do a quick throw-in of its LL3 nexus.
  • A kit, “mw_swarm_hive_nanites”, with one action. Nothing special about these nanites so no custom script is needed; just filling out its resource values.

Swarm hive nanites resource

License

  • To make a license, I have another resource, UnlockTree, that has three ranks and can have any number of kits and frames unlocked at any one. Let’s make one & add the balor.
  • Then we add this new license to the Horus Manufacturer. Here’s a snippet of my architectural megagraph that shows the relationships here.

LT resource graph

  • Let’s test ingame!
    • Use the map editor: swap out my test pilot’s mech for the Balor.
    • Run into a few small crashes: accidentally left a null in for one of the kit actions.
    • Forgot to add Regeneration’s action to its kit, so it wasn’t happen. Chalk one down to making the same number of mistakes even while writing a log.
    • Scouring Swarm didn’t leave any record in the log for where the damage was coming from; added that to its activation function.
    • Finally, when we copy+pasted CPJ’s anti-structure, we didn’t account for a few changes that needed to be made from
  • Other than that looks good. Let’s check it off of the content sheet!

Content sheet checkoff for Balor

All SSC & HORUS mechs, pilot barks, visual landscape palette