For “doing things the hard way”, when you want your equipment/skills/whatnot to do more than what vanilla does.

This page assumes you're using the standard Haxe symbols rather than the Dicey csv-compatible ones (so and not ~, , and not | or [;], || and not #). If you're writing directly to the csv (which is pretty common!), make sure to use the correct symbols.

Creating objects from template

The general format to do this is:

var [variable name] = new elements.[object type, Sentence case]([template to make object with]);

So if you want to make a Sword, (making care to replace quotation marks with tildes if manually editing the csv) you would do:

var coolsword = new elements.Equipment("Sword");

Or if you want a dummy fighter (for example Loud Bird):

var dummyenemy = new elements.Fighter("Loud Bird");

And if you want to make and reference a skill from template (for example Meganudge):

var dummyskill = new elements.Skill("Meganudge"); and equipment objects

There are four ways to give equipment to the player:

  • giveequipment. This is the easiest way to give equipment, but cannot be used before the start of your turn or after your turn has ended.
  • replacemewith. Unlike giveequipment, this is always permanent. But it does have a nice animation for swapping out equipment.
  • eq.create. This instantly replaces a targeted equipment with a new equipment you directly create from template using the command. However, you then need to separately track down the equipment you've just spawned before you can do anything with it, e.g. correct its position.
  • Manually declaring an equipment and pushing into or replacing an item in with it. This is essentially a more robust form of eq.create in that you do not need to track down the equipment to do something to it after you add it - you'll already have it as its own variable. Note however that directly attempting to replace e fails, and you cannot automatically transmute one object into a copy of another, so use instead. For example, say you want a script that just replaces the equipment it's attached to with Hookshot:
var hookshot = new elements.Equipment("Hookshot");
hookshot.x = e.x;
hookshot.y = e.y;[] = hookshot;

Since this will be instantaneous, you may want to add hookshot.animate(“flashandshake”) if this happens on-screen. (Note that e.animate(“flashandshake”) will not work because e is no longer in your equipment array.)

Dummy fighters

Dummy fighters can be used to check whether a status is set to alternate or not.

2022 UPDATE… HELLO FROM THE FUTURE WHERE RUNSCRIPT CAN BE USED TO ACCESS RULES ANYWHERE. var Rules = runscript(“getrules”); where getrules.hx is just return Rules;, then if(Rules.hasalternate(“ice”)) trace(“ice is alternate!”); where you replace ice with whatever you want to check. the part about using dummy fighters to call combat-only scripts is still relevant except getequipment() doesn't exist anymore and i'm pretty sure getequipmentlist() can be used in generators

Say you want to check whether freeze is alternate:

var freezeisalt = false;
var dummyfighter = new elements.Fighter("Wisp"); /*enemy is arbitrary as long as it's not immune to freeze*/
for(stat in dummyfighter.status) {
  if(stat.type == "alternate_ice") {
    freezeisalt = true;
if(freezeisalt) {
  /*do what you would do if freeze is alternate*/
} else {
  /*do what you would do if freeze is normal*/

They can also be used in non-combat environments to call code that normally only works in combat. For example, you could do this in a generator to get a list of all non-special equipment, even though getequipment() only works when called by a fighter:

var testdummy = new elements.Fighter("Wisp");
vat testskill = new elements.Skill("Meganudge");
testskill.script = "self.setvar(\"allequipment\",getequipment());";
var allequipment = testdummy.getvar("allequipment");

Storing code snippets as skills & executing them

Say you have a really long code snippet you need to copy and paste everywhere to get a custom status to work. You can reduce it a bit by making an entry in items.csv with that code in it, then declaring a skill with the entry name and executing it:

var dostatusstuff = new elements.Skill("internal status thing");

(self,target) means the fighter executing this script is you, and the fighter being targeted by the script is the enemy. This is pretty standard for most scripts.

Also, note that the AI will not be able to correctly handle executing skills. You should wrap the part with the skill declaration/execution in if(!simulation) { }. If the skill handles something that happens to the AI itself on its own turn, you're out of luck, and you'll need to unpack the script.

Note that using e will require a bit of kludgery since skill scripts have no way of telling what e is supposed to be unless a variable is explicitly assigned to e within the script. Have something like this at the start of the script you'll be executing, in this case for a skill named “internal item”:

var e = self.getvar("thisequipment");

And do this when you execute it:

var examplescript = new elements.Skill("internal item");

self.resetvar(“thisequipment”) is required since the game currently crashes if you end a battle while an equipment or array of equipment as one of your selfvars.

Scripts of skills can be manually modified. Here's a script for a card that executes a script of another random card you have, but needs some setup in order for things to work right:

var emulatethiseq = rand(;
var testscript = new elements.Skill("Against all odds_old");
testscript.script = emulatethiseq.script;
testscript.script = "var e = self.getvar(\"thisequipment\"); " + testscript.script;

Note that if there is sfx associated with the provided skill in equipmentsounds.json, it will play. Against all odds_old is a skill with no sfx that will likely not be removed or be given sfx any time soon.

Reversing the self and target parameters can let you do things like force the target to flee. The following snippet will cause the target to immediately run away, since Jetpack by default just contains “flee();”:

var runaway = new elements.Skill("Jetpack");

Since the game merely throws an error if a skill fails to execute rather than crashing or abandoning the original script, you can use skills as a sort of rudimentary try/catch mechanism. For example:

var trythis = new elements.Skill("code i'm not sure will work");
trythis.script = trythis.script + " self.setvar(\"diditwork\",\"yes\");";
if(self.getvar("diditwork") == "yes") {
  /*do what you'd do if it works*/
} else {
  /*do what you'd do if it didn't work*/

Script injection

Basically, fighters have their own script hooks for before combat, before start turn, on start turn, end turn, and after combat (last one might not be a thing?). So if the enemy is Sorceress, target.scriptbeforecombat would be the script that sets up her equipment layout. These script hooks can have scripts put in them as strings.

Equipment script hooks (before execute, on execute, on any equipment use, before start turn, etc.) are also accessible and can be modified.

Overall these are all the names you need to know:

  • scriptbeforecombat
  • scriptbeforestartturn
  • scriptonstartturn
  • scriptendturn
  • scriptaftercombat
  • script (just “script”, on execute - for this you'll also have to set e.scriptrunner to null or the game will just run the last script this equipment ran)
  • scriptbeforeexecute
  • scriptonanyequipmentuse
  • scriptonanycountdownreduce

Todo: go into more detail, look up what “on any countdown reduce” and “on fury” hook names are if they aren't exactly what they'd sound like.

Modifying map nodes

Here's a function:

function specialenemychat(floor) {
	for (node in floor.nodes) {
	  if (node.enemytemplate != null && == "Rhino Beetle") {
		node.enemytemplate.firstwords = "This is my special|boss-like dialogue|with 2 line breaks!||This is another dialogue box!"; node.enemytemplate.alwayssayfirstwords = true;

Add this function to a generator. When you generate each floor, assign it to a variable (e.g. floorx where x is the floor number) the way the last floor is assigned to lastfloor. Then after the floor is generated, call specialenemychat with that floor variable as the argument. This will make Rhino Beetle have special first words, like a boss would, before every fight. (While you can also accomplish this by adding to the “first words” column in Rhino Beetle's .csv, you can not have the first words be picked randomly from a pool, whereas with generator tricks you could do node.enemytemplate.firstwords = rand([“Dialogue 1”,”Dialogue 2“]);)

Here's all the different things an enemy template possesses:

  • name: string
  • health: integer
  • superhealth: integer
  • dice: integer
  • superdice: integer
  • level: integer
  • scriptbeforecombat: string
  • scriptaftercombat: string
  • scriptbeforestartturn: string
  • scriptonstartturn: string
  • scriptendturn: string
  • equipment: array of strings
  • superequipment: array of strings
  • skills: array of strings
  • alwayssayfirstwords: boolean
  • alwayssaylastwords: boolean
  • lastwords1: string
  • lastwords2: string
  • lastwords3: string
  • lastwords_iftheywin: string
  • lastwords_endgame: string
  • lastwordprogress: integer
  • firstwords: string
  • kludge_introfirstwords: boolean
  • description: string
  • innate: array of strings
  • ai: string
  • hassuper: boolean
  • boss: boolean
  • rare: boolean
  • combatAnimation: string
  • overworldAnimation: string
  • vfxoffset: coordinate pair
  • combatanimationoffset: coordinate pair
  • overworldanimationoffset: coordinate pair
  • limit: string
  • alternatelimit: string
  • voice: string
  • chatvoice: string
  • chatstyle: string

Todo: this is outdated! Do trace(target) and see what that spits out, maybe?


Shops, chests and trading booths also have templates, probably.

Call .toString() on a floor variable and you get some useful info. Todo: test this, actually write stuff.

Abusing Actuate for real-time effects

Hoo boy where to start with this. Actuators as we know them are exploits regarding the Actuate library and the creation of a SimpleActuator - an object used to handle smooth tweening (sliding) animations for graphics - which allow for realtime delays before scripts are processed, and scripts that repeatedly activate over an interval of time. If done right, they should look like this:

 if(self.getvar("myactuator") + 1 == "SimpleActuator1") {
 var tw = new motion.actuators.SimpleActuator(null,0.1,null);  
 var s = new elements.Skill("Against all odds_old");
 s.script = "
    /*code stuff. quotes here should be backslashed e.g. \"*/
    /*out clauses to stop the actuator should look like this:*/
    if(things) {
    /*the actuator should also stop if combat ends in any way. fighter.graphic is the literal graphic displayed by a fighter in battle; it's null if you're not in battle.*/
    if(self.hp <= 0 || self.graphic == null || target == null || target.graphic == null || target.hp <= 0) {
    /*if you're doing something like moving the player's equipment aside and giving them a few cards and a dice to make a selection; check whether self.doendturnnow ever turns true, and if so clean up immediately.*/
 tw._repeat = -1;

The second parameter in new motion.actuators.SimpleActuator is the initial delay and how much time in seconds passes between each repeat of the actuator. tw._repeat just determines how many times the actuator should repeat before it stops automatically. -1 means repeat forever, much like how an equipment with -1 uses is infinitely reuseable. Note tw and s in this case are both arbitrary variable names.

If for some reason you're dead-set on elegance or conciseness and want an actuator that only executes a single command (which almost definitely means it shouldn't repeat infinitely), the arguments taken by tw.onRepeat are a function and then an array of that function's arguments, so you could do for example:


If you want an actuator that doesn't repeat, and simply acts like a delayed command rather than a while loop, keep in mind tw.onComplete. E.g.

 var tw = new motion.actuators.SimpleActuator(null,0.01,null);
 var s = new elements.Skill("Against all odds_old");
 s.script = "my awesome code";
 tw.onComplete(s.execute,[self,target]); tw.move();

You can also construct an instance of the hscript parser and have onRepeat parse a string instead of executing it, which allows for more flexibility in what you can do with the actuator, but if you actually care about that then your name is either Jackeea, TheMysticSword, Wisp, or Kirb. Or Cody. Todo!

User Tools