HASL is a scripting language designed for 2D game engines. It uses an assembly-style syntax in which each instruction performs a simple, explicit operation. It contains the core features necessary for any general purpose language (math, control flow, memory manipulation), while also being integrated directly with the engine and supporting user-defined functionality.
Scripts are read in from a file and parsed into an ordered list of commands. Every time a script is run, these commands are executed in order from the entry point. Each script has access to its own set of general purpose registers: 26 64-bit signed integer registers, 14 64-bit double-precision floating-point registers, and 12 vector registers (where each vector is a pair of 32-bit single-precision floating-point values). Additionally, each script has its own 8KB stack and 4KB of memory.
Documentation for a very similar language I made for the Game Development Workshop Series is available here.
A simple script that has a Camera follow its target directly:
# bind object 0 (the target)
mov 0, $obj
# get the target's position and negate it
ogp $v0
mulv $v0, -1., $v0
# bind the Camera
mov $hst, $obj
# set the Camera's position
osp $v0
A simple script to move the player using the keyboard:
# bind the player
mov $hst, $obj
# get x-axis move direction (A and D keys)
ikd 68, 65, $t0
# get y-axis move direction (W and S keys)
ikd 87, 83, $t1
# create move direction vector
movx $t0, $v0
movy $t1, $v0
# multiply move direction by player's speed (because we're multiplying by speed, we don't need to divide by sqrt(2) if necessary because the vector is clamped in Scriptable::SetVel, which has the same effect. If we were using a vector of smaller magnitude, we would need to do that calculation)
ogs $f0
mulv $v0, $f0, $v0
# set player's velocity to computed vector
osv $v0
# update player's state accordingly (this assumes our player has two different Sprites - one called "move" and the other "idle")
beqz $v0, state_idle
oss "move"
j state_end
state_idle:
oss "idle"
state_end:
end
A more complex script to recursively generate the n
th Fibonacci number:
fib:
# save calling frame's values on the stack
psh $a0
psh $s0
# $s0 will store the result of fib($a0)
mov $a0, $s0
# if $a0 < 2, just return it (fib(1) is 1 and fib(0) is 0)
mov 2, $t0
blt $a0, $t0, fib_e
# $s0 = 0
mov 0, $s0
# $s0 += fib($a0 - 1)
sub $a0, 1, $a0
call fib
add $s0, $r0, $s0
# $s0 += fib($a0 - 2)
sub $a0, 1, $a0
call fib
add $s0, $r0, $s0
fib_e:
# move result into return register
mov $s0, $r0
# recover calling frame's values and return
pop $s0
pop $a0
ret
main:
# calculate fib numbers 0-40
mov 40, $s1
mov -1, $s2
loop:
# exit if index == -1
beq $s1, $s2, main_e
# calculate current fib number
mov $s1, $a0
call fib
# print
dbg $r0
# decrement index and loop
sub $s1, 1, $s1
j loop
main_e:
end