# Escape the Wolf OHR

########################################################################

include, plotscr.hsd
include, scancode.hsi

#-----------------------------------------------------------------------

define constant(1, zone:clearing)
define constant(2, zone:home)
define constant(3, zone:well)
define constant(1, wolf)
define constant(2, cabin)
define constant(15, loglen)
define constant(1, timer:flash)
define constant(2, timer:exhaustion)
define constant(3, timer:well)

global variable(1, is running)
global variable(2, meta)
global variable(3, wolf strategy)
global variable(4, hud)
global variable(5, flash)
global variable(6, ticks)
global variable(7, exhausted)
global variable(8, cheat count)
global variable(9, easiness)

########################################################################

plotscript, new game, begin
  pick difficulty
  init meta
  init hud
  init player
  init wolf
  build cabin
  grow the forest
  show help
  game loop
end

script, pick difficulty, begin
  variable(sl)
  sl := load slice collection(0)
  free slice(lookup slice(10, sl))
  open menu(4)
  wait(1)
  free slice(sl)
end

plotscript, easy mode, begin
  easiness := 2
end

plotscript, medium mode, begin
  easiness := 1
end

plotscript, hard mode, begin
  easiness := 0
end

########################################################################

script, game loop, begin
  wolf howl
  while(true) do(
    player controls
    wolf action
    update
    wait(1)
    ticks += 1
  )
end

script, update, begin
  variable(who)
  for(who, me, wolf) do(
    update unit(who)
  )
  player fatigue
  check for well
  check for safe house
end

script, update unit, who, begin
  variable(d, x, y)
  d := get want go(who)
  if(d >= 0) then(
    # wants to move
    log move(who)
    make footprints(who)
    x := ahead x from(hero x(who), d)
    y := ahead y from(hero y(who), d)
    if(wrap read pass block(x, y) == 0) then(
      walk hero(who, d)
      cancel walk(who)
    )
    set idle(who, 0)
  )else(
    # doesn't want to move
    idle(who)
  )
end

########################################################################

plotscript, show help, begin
  variable(sl)
  sl := load slice collection(2)
  wait(4)
  wait for key
  free slice(sl)
  sl := load slice collection(3)
  camera follows hero(cabin) # show the cabin
  wait(4)
  wait for key
  free slice(sl)
  camera follows hero(me)
end

########################################################################

script, init player, begin
  cancel walk(me)
  set hero position(me, map width / 2, map height / 2)
  create clearing(hero x(me), (hero Y(me) + 4), 6)
  suspend player
  suspend hero walls
  suspend caterpillar
end

script, init wolf, begin
  add hero(1)
  set hero position(wolf, hero x(me) + random offset(16, 18), hero y(me) + random offset(16, 18))
  create clearing(hero x(wolf), hero y(wolf), 3)
end

script, random offset, min, max, begin
  variable(n)
  n := random(min, max)
  if(random(0, 1) == 0) then(n := n * -1)
  exit returning(n)
end

########################################################################

script, wolf action, begin
  variable(xd, yd, range)
  if(hero is walking(wolf)) then(exit script)
  xd := hero x(me) -- hero x(wolf)
  yd := hero y(me) -- hero y(wolf)
  if(abs(xd) >> map width / 2) then(xd := xd * -1)
  if(abs(yd) >> map height / 2) then(yd := yd * -1)
  range := get wolf range(xd, yd)
  switch(wolf strategy) do(
    case(strat:wait) do(not chasing(xd, yd))
    case(strat:simple) do(simple chase(xd, yd))
    case(strat:flank) do(flanking chase(xd, yd)) 
    case(strat:circle) do(circling chase(xd, yd)) 
    case(strat:cheat) do(cheating chase(xd, yd)) 
  )
  set hero speed(wolf, 10)
  if(easiness >> 0) then(
    # except on max difficulty, the wolf runs slower than you.
    if(ticks ,mod, (10/easiness) == 0) then(
      set hero speed(wolf, 5)
    )
  )
  if(range == 0) then(
    # very close!
    set hero speed(wolf, 5)
    if(random(0, 100) << 3) then(wolf growl)
  )
  if(range == 1 && not(is running)) then(
    # semi close, only runs if you do
    set hero speed(wolf, 5)
  )
  walk into trees(wolf)
  check for stuck wolf
  check for bite
end

define constant(4, total strategies)
script, check for stuck wolf, begin
  if(full log(wolf)) then(
    if(travelled sq(wolf) <= 3^2) then(
      wolf howl
      wolf strategy := (wolf strategy + 1) ,mod, total strategies
      flush log(wolf)
      #$0="wolf stuck, change strategy to ", append number(0, wolf strategy), trace(0)
    )
  )
end

define constant(-1, strat: wait)
script, not chasing, xd, yd, begin
end

define constant(0, strat:simple)
script, simple chase, xd, yd, begin
  if(abs(xd) >> abs(yd)) then(
    if(xd >> 0) then(lope(east))
    if(xd << 0) then(lope(west))
  )else(if(abs(xd) << abs(yd)) then(
    if(yd >> 0) then(lope(south))
    if(yd << 0) then(lope(north))
  )else(
    mimic chase(xd, yd)
  ))
end

define constant(1, strat:flank)
script, flanking chase, xd, yd, begin
  if(abs(xd) >> abs(yd)) then(
    if(yd >> 0) then(lope(south))
    if(yd << 0) then(lope(north))
  )else(if(abs(xd) << abs(yd)) then(
    if(xd >> 0) then(lope(east))
    if(xd << 0) then(lope(west))
  )else(
    mimic chase(xd, yd)
  ))
end

define constant(2, strat:circle)
script, circling chase, xd, yd, begin
  simple chase(xd, yd)
  set want go(wolf, rotate(get want go(wolf), 1))
end

define constant(3, strat:cheat)
script, cheating chase, xd, yd, begin
  variable(sq)
  sq := abs(xd)^2 + abs(yd)^2
  if(sq >> 40) then(
    # cheat teleport
    while(true) do(
      set hero position(wolf, hero x(wolf) + sign(xd), hero y(wolf) + sign(yd))
      if(wrap read pass block(hero x(wolf), hero y(wolf)) == 0) then(break)
    )
    #$0="TELEPORT! ", append number(0, hero x(wolf)), $0+",", append number(0, hero y(wolf)), trace(0)
    wolf strategy := strat:simple
  )else(
    simple chase(xd, yd)
  )
end

script, mimic chase, xd, yd, begin
  switch(hero direction(me)) do(
    case(north) do(
      if(yd <= 0) then(lope(north), exit script)
      if(yd >= 0) then(lope(south), exit script)
    )
    case(south) do(
      if(yd >= 0) then(lope(south), exit script)
      if(yd <= 0) then(lope(north), exit script)
    )
    case(west) do(
      if(xd <= 0) then(lope(west), exit script)
      if(xd >= 0) then(lope(east), exit script)
    )
    case(east) do(
      if(xd >= 0) then(lope(east), exit script)
      if(xd <= 0) then(lope(west), exit script)
    )
  )
end

script, lope, d, begin
  set want go(wolf, d)
  set hero direction(wolf, d)
end

script, get wolf range, xd, yd, begin
  variable(dist sq)
  dist sq := abs(xd)^2 + abs(yd)^2
  if(dist sq <= (3 + easiness)^2) then(play song(1), exit returning(0))
  if(dist sq <= (6 + easiness)^2) then(play song(1), exit returning(1))
  if(dist sq <= (9 + easiness)^2) then(play song(0), exit returning(2))
  play song(0), exit returning(5)
end

script, check for bite, begin
  variable(xd, yd, sq)
  if(wolf strategy == strat:wait) then(exit script)
  xd := hero pixel x(me) -- hero pixel x(wolf)
  yd := hero pixel y(me) -- hero pixel y(wolf)
  sq := abs(xd)^2 + abs(yd)^2
  if(sq << 10^2) then(
    wolf bite
    wolf strategy := strat:wait
    knockback(me, hero direction(wolf))
    lose heart
  )
end

script, knockback, who, d, begin
  variable(od)
  if(hero is walking(who) || get want go(who) >= 0) then(exit script)
  od := hero direction(who)
  set hero speed(who, 10)
  if(get want go(who) << 0) then(
    set want go(who, d)
    set hero direction(who, od)
  )
end

script, wolf howl, begin
  if(sound is playing(1) || sound is playing(2)) then(exit script)
  play sound(random(1, 2))
end

script, wolf growl, begin
  if(sound is playing(0)) then(exit script)
  play sound(0)
end

script, wolf bite, begin
  if(sound is playing(3)) then(exit script)
  play sound(3)
end

########################################################################

script, player controls, begin
  if(keyval(key:ESC) >> 1) then(open menu(1))
  if(key is pressed(key:comma)) then(camera follows hero(me))
  if(key is pressed(key:period)) then(camera follows hero(wolf))
  if(hero is walking(me)) then(exit script)
  if(run requested && not(exhausted)) then(
    player running controls
  )else(
    player walking controls
  )
  walk into trees(me)
end

script, run requested, begin
  exit returning(key is pressed(key:space) >> 0 || key is pressed(key:ctrl) || key is pressed(key:shift))
end

script, player walking controls, begin
  player motion controls(@walk)
end

script, player running controls, begin
  player motion controls(@run)
end

script, player motion controls, motion script, begin
  if(keyval(key:up) >> 0)    then(run script by id(motion script, north), exit script)
  if(keyval(key:down) >> 0)  then(run script by id(motion script, south), exit script)
  if(keyval(key:left) >> 0)  then(run script by id(motion script, west), exit script)
  if(keyval(key:right) >> 0) then(run script by id(motion script, east), exit script)
end

script, player fatigue, begin
  if(get vigor << 2) then(
    become exhausted
  )
  if(exhausted) then(
    adjust vigor(1)
  )
  if(get idle(me) >= 2) then(
    adjust vigor(1)
    exit script
  )
  if(is running) then(
    if(ticks ,mod, 2 == 0) then(
      adjust vigor(-1)
    )
    exit script
  )
  if(ticks ,mod, 2 == 0) then(
    adjust vigor(-1)
  )
end

script, become exhausted, begin
  exhausted := true
  set hero picture(me, 2)
  $0="EXHAUSTED!", notify(0)
  set timer(timer:exhaustion, 3, 18, @end exhaustion)
  play sound(6)
end

script, end exhaustion, begin
  exhausted := false
  set hero picture(me, 0)
  clear notify
end

script, player death, begin
  variable(i, sl, w, r, nom)
  play song(2)
  wait(1)
  sl := load slice collection(5)
  w := lookup slice(8, sl)
  r := lookup slice(9, sl)
  play sound(4)
  i := 0
  while(true) do(
    if(i / 20 ,mod, 2 == 0) then(
      if(not(nom)) then(play sound(5), nom := true)
      # Red twitches
      set slice x(r, random(-1, 1))
      set slice y(r, random(-1, 1))
      # Wolf gnaws
      set slice x(w, (i ,mod, 4))
      set slice y(w, (i ,mod, 4))
    )else(
      nom := false
    )
    i += 1
    wait(1)
    if(i >> 10) then(
      if(keyval(key:space) >> 1 || keyval(key:ctrl) >> 1 || keyval(key:shift) >> 1 || keyval(key:enter) >> 1) then(break)
    )
  )
  open menu(2)
  wait(1)
  free slice(sl)
end

plotscript, menu reset, begin
  reset game
end

plotscript, menu cheat, begin
  set hearts(3)
  set vigor(150)
  set hero position(wolf, hero x(me) + random offset(18, 25), hero y(me) + random offset(18, 25))
  wolf strategy := strat:cheat
  cheat count += 1
  $0="Cheated ", append number(0, cheat count), $0+" times.", notify(0)
end

#-----------------------------------------------------------------------

script, walk, d, begin
  set hero speed(me, 4)
  set want go(me, d)
  set hero direction(me, d)
  is running := false
end

script, run, d, begin
  set hero speed(me, 10)
  set want go(me, d)
  set hero direction(me, d)
  is running := true
end

script, player collide while running, begin
  set hero speed(me, 5)
end

script, cancel walk, who, begin
  set want go(who, -1)
end

#-----------------------------------------------------------------------

script, walk into trees, who, begin
  variable(x, y)
  if(get want go(who) >= 0) then(
    x := ahead x(who)
    y := ahead y(who)
    if(wrap read pass block(x, y) <> 0) then(
      shunt sideways(who, x, y)
    )
  )
end

script, shunt sideways, who, x, y, begin
  variable(order)
  order := 1#random(0, 1)
  if(order == 0) then(
    if(not(shunt left(who, x, y))) then(
      if(not(shunt right(who, x, y))) then(
        cancel walk(who)
      )
    )
  )else(
    if(not(shunt right(who, x, y))) then(
      if(not(shunt left(who, x, y))) then(
        cancel walk(who)
      )
    )
  )
end

script, shunt left, who, x, y, begin
  exit returning(shunt turn(-1, who, x, y))
end

script, shunt right, who, x, y, begin
  exit returning(shunt turn(1, who, x, y))
end

script, shunt turn, turn, who, x, y, begin
  variable(hero d, shunt d)
  hero d := hero direction(who)
  shunt d := rotate(hero d, turn)
  x := ahead x(x)
  y := ahead y(y)
  if(wrap read pass block(x, y) == 0) then(
    x := ahead x from(hero x(who), shunt d)
    y := ahead y from(hero y(who), shunt d)
    if(wrap read pass block(x, y) == 0) then(
      if(who == 0 && is running) then(player collide while running)
      set want go(who, shunt d)
      exit returning(true)
    )
  )
  exit returning(false)
end

script, ahead x from, x, d, begin
  if(d == west) then(exit returning(x -- 1))
  if(d == east) then(exit returning(x + 1))
  exit returning(x)
end

script, ahead y from, y, d, begin
  if(d == north) then(exit returning(y -- 1))
  if(d == south) then(exit returning(y + 1))
  exit returning(y)
end

script, ahead x, who, begin
  exit returning(ahead x from(hero x(who), hero direction(who)))
end

script, ahead y, who, begin
  exit returning(ahead y from(hero y(who), hero direction(who)))
end

script, rotate, cardinal, change, begin
  #cardinal is 0-3 clockwise. change is -1 or +1
  cardinal += change
  while(cardinal >> west) do(cardinal -= 4)
  while(cardinal << north) do(cardinal += 4)
  exit returning(cardinal)
end

########################################################################

script, create clearing, x, y, radius, zone=zone:clearing, begin
  variable(tx, ty)
  for(ty, y -- 7, y + 7) do(
    for(tx, x -- 7, x + 7) do(
      if(abs(x -- tx)^2 + abs(y -- ty)^2 <= radius ^ 2) then(
        wrap write map block(tx, ty, 2, 0)
        wrap write zone(zone, tx, ty, true)
      )
    )
  )
end

script, make footprints, who, begin
  variable(tile, d)
  tile := wrap read map block(hero x(who), hero y(who), 1)
  if(tile == 0 || tile == 9 || tile == 10) then(
    d := hero direction(who)
    if(d == north || d == south) then(
      tile := 9
    )else(
      tile := 10
    )
    wrap write map block(hero x(who), hero y(who), tile, 1)
  )
end

########################################################################

script, build cabin, begin
  variable(x, y, sq, fx, fy, tx, ty, tile)
  # find a random corner
  while(true) do(
    x := random(5, map width -- 6)
    y := random(5, map height -- 6)
    sq := abs(x -- map width / 2)^2 + abs(y -- map height / 2)^2
    #$0="CABIN SITE x=", append number(0, x), $0+" y=", append number(0, y), trace(0)
    if(sq >= (map width / 2)^2) then(break)
  )
  create clearing(x, y + 4, 7)
  # cabin base
  ty := 5
  for(fy, y -- 1, y + 1) do(
    tx := 0
    for(fx, x -- 2, x + 2) do(
      tile := ty * 16 + tx
      wrap write map block(fx, fy, tile, 1)
      tx += 1
    )
    ty += 1
  )
  for(fx, x -- 1 , x + 1) do(
    wrap write pass block(fx, y, northwall+southwall+eastwall+westwall)
  )
  # door zone
  wrap write zone(zone:home, x, y + 1, true)
  # cabin roof
  ty := 8
  for(fy, y -- 2, y -- 1) do(
    tx := 9
    for(fx, x -- 2, x + 2) do(
      tile := ty * 16 + tx
      wrap write map block(fx, fy, tile, 2)
      tx += 1
    )
    ty += 1
  )
  # camera focus point
  set hero position(cabin, x, y)
  build footpath(x, y + 2)
end

script, build footpath, start x, start y, begin
  variable(i, j, x, y, d, d1, d2, tile)
  d1 := random(north, west)
  if(random(0, 1))
    then(d2 := rotate(d1, -1))
    else(d2 := rotate(d1, 1))
  #$0="favor=", append number(0, d1), $0+" secondary=", append number(0, d2), trace(0)
  x := start x
  y := start y
  d := d1
  if(d1 == north) then(d := d2)
  j := random(1, 5)
  while(i << map width / 3 + (easiness * map width / 5)) do(
    tile := 68 + (i ,mod, 6)
    if(wrap read map block(x, y, 1) == 0) then(
      wrap write map block(x, y, tile, 1)
    )
    wrap write zone(zone:clearing, x+1, y, true)
    wrap write zone(zone:clearing, x--1, y, true)
    wrap write zone(zone:clearing, x, y+1, true)
    wrap write zone(zone:clearing, x, y--1, true)
    x := ahead x from(x, d)
    y := ahead y from(y, d)
    x := wrap x(x)
    y := wrap y(y)
    #$0="X=", append number(0, x), $0+" Y=", append number(0, y), trace(0)
    if(j <= 0) then(
      # change direction
      j := random(2, 6)
      if(random(0, 1) == 0) then(
        d := d1
      )else(
        if(random(0, 3) >> 0) then(
          d := d2
        )else(
          d := rotate(d2, 2)
        )
      )
      #$0="footpath change ", append number(0, d), trace(0)
    )
    i += 1
    j -= 1
  )
  create clearing(x, y + 4, 6)
  create clearing(x, y, 2, zone:well)
  wrap write map block(x, y, 101, 1)
  wrap write pass block(x, y, northwall+southwall+eastwall+westwall)
  
end

script, check for well, begin
  if(wrap read zone(zone:well, hero x(me), hero y(me))) then(
    $0="THE WELL! THE CABIN CAN'T BE FAR!", notify(0)
    stop timer(timer:well)
    set timer(timer:well, 2, 18, @clear notify)
  )
end

script, check for safe house, begin
  if(wrap read zone(zone:home, hero x(me), hero y(me))) then(
    made it home safe
  )
end

script, made it home safe, begin
  variable(i, sl, w, r, t, t2, spr)
  play song(3)
  
  fade screen out
  wait(1)
  sl := load slice collection(4)
  w := lookup slice(5, sl)
  r := lookup slice(6, sl)
  t := lookup slice(7, sl)
  t2 := lookup slice(11, sl)
  if(easiness == 0 && cheat count == 0) then(
    $0="(YOU GOT THE BEST ENDING!)"
    set slice text(t2, 0)
  )

  $0=" TIME = "
  if(hours of play >> 0) then(append number(0, hours of play), $0+"hour ")
  if(minutes of play >> 0) then(append number(0, minutes of play), $0+"min ")
  append number(0, seconds of play), $0+"sec "
  if(cheat count >> 0) then($0+"CHEATED ", append number(0, cheat count), $0+" TIMES")
  set slice text(t, 0)
  
  wait(1)
  fade screen in
  
  wait(18 * 3)
  
  # move wolf into window
  while(true) do(
    set slice x(w, slice x(w) -- 3)
    set slice y(w, slice y(w) -- 3)
    if(slice y(w) << -5) then(break)
    wait(1)
  )

  for(i, 1, 12) do(
    set slice x(w, slice x(w) ,xor, (i ,mod, 2))
    wait(1)
  )
  
  replace backdrop sprite(r, 7)
  
  i := 0
  while(true) do(
    i += 1
    if(i >> 10 * 3 && easiness == 0 && cheat count == 0) then(
      # special ending
      if(i ,mod, 34 == 0) then(
        spr := get sprite set number(w)
        if(spr == 4) then(
          replace backdrop sprite(r, 10)
          replace backdrop sprite(w, 11)
        )else(
          spr += 1
          if(spr >> 14) then(spr := 11)
          replace backdrop sprite(w, spr)
        )
      )
    )else(
      #regular ending
      # Red laughs
      if((i / 3) ,mod, 2 == 0) then(
        set slice y(r, slice y(r) + 1)
      )else(
        set slice y(r, slice y(r) -- 1)
      )
    )
    # Wolf seeths
    set slice x(w, slice x(w) + random(-1, 1))
    set slice y(w, slice y(w) + random(-1, 1))
    if(slice x(w) >> 3 || slice x(w) << -3) then(set slice x(w, 0))
    if(slice y(w) >> 3 || slice y(w) << -3) then(set slice y(w, 0))
    wait(1)
    if(keyval(key:space) >> 1 || keyval(key:ctrl) >> 1 || keyval(key:shift) >> 1 || keyval(key:enter) >> 1) then(break)
  )

  open menu(3)
end

########################################################################

script, grow the forest, begin
  variable(y, i, tree rate, row total, sl)
  sl := load slice collection(0)
  wait(1)
  tree rate := 40 # Approx 1 tree for this many tiles
  for(y, 0, map height -- 1) do(
    row total := map width / tree rate
    for(i, 1, row total) do(
      grow a random tree(y)
    )
  )
  free slice(sl)
end

script, grow a random tree, y, begin
  variable(x, size, safety)
  size := random(0, 1)
  while(true) do(
    x := random(0, map width -- 1)
    if(okay to grow a tree(x, y)) then(break)
    safety += 1
    if(safety >> 25) then($0="couldn't find a place for a random tree on row ", append number(0, y), trace(0), exit script)
  )
  grow a tree(x, y, size)
end

script, okay to grow a tree, x, y, begin
  if(x << 0) then(exit returning(false))
  if(y << 0) then(exit returning(false))
  if(x >= map width) then(exit returning(false))
  if(y >= map height) then(exit returning(false))
  if(wrap read zone(zone:clearing, x, y)) then(exit returning(false))
  if(wrap read pass block(x, y) <> 0) then(exit returning(false))
  exit returning(true)
end

script, grow a tree, x, y, size, begin
  switch(size) do(
    case(0) do(grow a small tree(x, y))
    case(1) do(grow a big tree(x, y))
  )
end

script, grow a small tree, x, y, begin
  variable(i, high, foly, shadx, shadtile)
  # stump
  wrap write map block(x, y, 150, 2)
  wrap write pass block(x, y, (northwall+southwall+eastwall+westwall))
  # trunk
  high := random(1, 3)
  foly := y
  shadx := x
  wrap write map block(x, y, 5, 0) # shadow base
  shadtile := 4
  for(i, 0, high) do(
    foly -= 1
    wrap write map block(x, foly, 134, 2)
    shadx -= 1
    if(i == high) then(shadtile := 3)
    wrap write map block(shadx, y, shadtile, 0)
  )
  foly -= 1
  shadx -= 2
  # foliage
  grow foliage(x, foly)
  # foliage shadow
  foliage shadow(shadx, y)
end

script, grow a big tree, x, y, begin
  variable(i, j, high, foly, shadx, shadtile)
  # stump
  for(i, -1, 1) do(
    wrap write map block(x + i, y, 148 + i, 2)
    wrap write pass block(x + i, y, (northwall+southwall+eastwall+westwall))
    wrap write pass block(x + i, y -- 1, (northwall+southwall+eastwall+westwall))
  )
  # trunk
  high := random(2, 4)
  foly := y
  shadx := x
  wrap write map block(x, y, 8, 0) # shadow base
  shadtile := 7
  for(i, 0, high) do(
    foly -= 1
    for(j, -1, 1) do(
      wrap write map block(x + j, foly, 132 + j, 2)
    )
    shadx -= 1
    if(i == high) then(shadtile := 6)
    wrap write map block(shadx, y, shadtile, 0)
  )
  foly -= 1
  shadx -= 2
  # foliage
  grow foliage(x, foly)
  # foliage shadow
  foliage shadow(shadx, y)
end

script, grow foliage, x, y, begin
  if(random(0, 2) << 2) then(
    grow round foliage(x, y)
  )else(
    grow pine foliage(x, y)
  )
end

script, grow round foliage, x, y, begin
  variable(fx, fy, tx, ty, tile, layer)
  for(fy, y -- 3, y + 2) do(
    tx := 1
    for(fx, x -- 3, x + 3) do(
      tile := ty * 16 + tx
      if(not(tile == 1 || tile == 7 || tile == 81 || tile == 87)) then(
        layer := next free overhead layer(fx, fy)
        if(layer <> -1) then(
          wrap write map block(fx, fy, tile, layer)
        )
      )
      tx += 1
    )
    ty += 1
  )
end

script, grow pine foliage, x, y, begin
  variable(fx, fy, tx, ty, tile, layer)
  for(fy, y -- 3, y + 2) do(
    tx := 8
    for(fx, x -- 2, x + 2) do(
      tile := ty * 16 + tx
      if(not(tile == 8 || tile == 9 || tile == 11 || tile == 12 || tile == 24 || tile == 28)) then(
        layer := next free overhead layer(fx, fy)
        if(layer <> -1) then(
          wrap write map block(fx, fy, tile, layer)
        )
      )
      tx += 1
    )
    ty += 1
  )
end

script, foliage shadow, x, y, begin
  variable(fx, fy, tx, ty, tile)
  for(fy, y -- 2, y + 2) do(
    tx := 10
    for(fx, x -- 3, x + 2) do(
      tile := ty * 16 + tx
      if(not(tile == 10 || tile == 15 || tile == 74 || tile == 79)) then(
        wrap write map block(fx, fy, tile, 0)
      )
      tx += 1
    )
    ty += 1
  )
end

script, next free overhead layer, fx, fy, begin
  variable(layer)
  for(layer, 2, 7) do(
    if (wrap read map block(fx, fy, layer) == 0) then(exit returning(layer))
  )
  return(-1)
end

########################################################################

script, init hud, begin
  hud := load slice collection(1)
  set vigor(150)
  set hearts(3)
end

script, set vigor, v, begin
  variable(bar)
  bar := lookup slice(2, hud)
  set slice height(bar, v)
end

script, get vigor, begin
  variable(bar)
  bar := lookup slice(2, hud)
  exit returning(slice height(bar))
end

script, adjust vigor, amount, begin
  variable(v)
  v := get vigor
  v += amount
  if(v << 0) then(v := 0)
  if(v >> 150) then(v := 150)
  set vigor(v)
end

script, set hearts, v, begin
  variable(bar)
  bar := lookup slice(1, hud)
  set slice height(bar, v * 10)
end

script, get hearts, begin
  variable(bar)
  bar := lookup slice(1, hud)
  exit returning(slice height(bar) / 10)
end

script, lose heart, begin
  variable(h)
  h := get hearts
  h -= 1
  red flash
  set hearts(h)
  if(h <= 0) then(
    h := 0
    player death
  )
end

script, red flash, begin
  if(flash) then(free slice(flash))
  flash := create rect
  fill parent(flash, true)
  set rect bg col(flash, 4)
  set rect trans(flash, trans:fuzzy)
  move slice below(flash, hud)
  set timer(timer:flash, 0, 1, @end flash)
end

script, end flash, begin
  if(flash) then(free slice(flash))
  flash := 0
end

########################################################################

script, init meta, begin
  meta := create container
  set slice visible(meta, false)
  add meta # for player
  add meta # for wolf
end

script, add meta, begin
  variable(sl)
  sl := create container
  add log(sl)
  set parent(sl, meta)
end

script, get meta, who, begin
  exit returning(slice child(meta, who))
end

#-----------------------------------------------------------------------

script, set want go, who, val, begin
  variable(sl)
  sl := get meta(who)
  set slice width(sl, val)
end

script, get want go, who, begin
  variable(sl)
  sl := get meta(who)
  exit returning(slice width(sl))
end

script, set idle, who, val, begin
  variable(sl)
  sl := get meta(who)
  set slice height(sl, val)
end

script, get idle, who, begin
  variable(sl)
  sl := get meta(who)
  exit returning(slice height(sl))
end

script, idle, who, begin
  variable(n)
  n := get idle(who)
  n += 1
  if((n ,mod, 2) == 0) then(log move(who))
  set idle(who, n)
end

script, clear notify, begin
  $0="", notify(0)
end

script, notify, str, begin
  variable(txt)
  txt := lookup slice(3, hud)
  set slice text(txt, str)
end

#-----------------------------------------------------------------------

script, add log, sl, begin
  variable(i, l)
  for(i, 1, log len) do(
    l := create rect(1, 1)
    set rect bg col(l, 15) # normally invisible, but can be visible for debugging
    set parent(l, sl)
    set slice x(l, -1)
    set slice y(l, -1)
  )
end

script, full log, who, begin
  variable(sl, l)
  sl := get meta(who)
  l := first child(sl)
  while(l) do(
    if(slice x(l) == -1) then(exit returning(false))
    l := next sibling(l)
  )
  exit returning(true)
end

script, flush log, who, begin
  variable(sl, l)
  sl := get meta(who)
  l := first child(sl)
  while(l) do(
    set slice x(l, -1)
    l := next sibling(l)
  )
end

script, log move, who, begin
  variable(sl, l)
  sl := get meta(who)
  l := last child(sl)
  set slice x(l, hero x(who))
  set slice y(l, hero y(who))
  slice to back(l)
end

script, travelled sq, who, begin
  variable(tx, ty)
  tx := travelled x(who)
  ty := travelled y(who)
  exit returning(abs(tx)^2 + abs(ty)^2)
end

script, travelled x, who, begin
  variable(sl, l, n, dist, max dist)
  sl := get meta(who)
  l := first child(sl)
  while(l) do(
    n := slice x(l)
    if(n >= 0) then(
      dist := hero x(who) -- n
      if(abs(dist) >> abs(max dist)) then(
        max dist := dist
      )
    )
    l := next sibling(l)
  )
  exit returning(max dist)
end

script, travelled y, who, begin
  variable(sl, l, n, dist, max dist)
  sl := get meta(who)
  l := first child(sl)
  while(l) do(
    n := slice y(l)
    if(n >= 0) then(
      dist := hero y(who) -- n
      if(abs(dist) >> abs(max dist)) then(
        max dist := dist
      )
    )
    l := next sibling(l)
  )
  exit returning(max dist)
end

########################################################################

script, wrap x, x, begin
  if(x << 0) then(exit returning(x + map width))
  if(x >= map width) then(exit returning(x -- map width))
  exit returning(x)
end

script, wrap y, y, begin
  if(y << 0) then(exit returning(y + map height))
  if(y >= map height) then(exit returning(y -- map height))
  exit returning(y)
end

script, wrap read pass block, x, y, begin
  x := wrap x(x)
  y := wrap y(y)
  exit returning(read pass block(x, y))
end

script, wrap write pass block, x, y, pass, begin
  x := wrap x(x)
  y := wrap y(y)
  write pass block(x, y, pass)
end

script, wrap read map block, x, y, layer, begin
  x := wrap x(x)
  y := wrap y(y)
  exit returning(read map block(x, y, layer))
end

script, wrap write map block, x, y, tile, layer, begin
  x := wrap x(x)
  y := wrap y(y)
  write map block(x, y, tile, layer)
end

script, wrap read zone, zone, x, y, begin
  x := wrap x(x)
  y := wrap y(y)
  exit returning(read zone(zone, x, y))
end

script, wrap write zone, zone, x, y, val, begin
  x := wrap x(x)
  y := wrap y(y)
  write zone(zone, x, y, val)
end

########################################################################