Scripts:Hero will move

From OHRRPGCE-Wiki
Jump to navigation Jump to search

If you want to make changes to hero movement animation, such as 3 or 4 frame animations, then you will likely want to know whether a hero will start moving this turn. "Each step" scripts don't trigger until after the hero has completed a movement of one tile. Also, the "hero is walking" command will return false if the hero has just finished a movement but will start a new one because the player is holding down an arrow key. So unfortunately there are no commands that can tell you that directly: you have to figure it out by checking keypresses and for obstructions (predicting what's about to happen), which is what this script does.

Beware that this script will break in lots of edge cases! Most of these are mentioned in the comments. Mostly significantly, it can't predict that you're about to call the "walk hero" command. Also note that these scripts are written to match how ichorescent and later versions handle pressing several arrow keys/dpad buttons at once; use old scripts (see History) for hróðvitnir and earlier.

For an example of its use, see below, or Scripts:Change hero sprite when standing still.


script, dir X, dir, begin
  switch (dir) do (
    case (up, down) do (return (0))
    case (right) do (return (1))
    case (left) do (return (-1))
  )
end

script, dir Y, dir, begin
  switch (dir) do (
    case (left, right) do (return (0))
    case (down) do (return (1))
    case (up) do (return (-1))
  )
end

# Returns the direction the hero will try to move, or else -1
script, want to move direction, begin
  return (-1)

  # If a textbox is up or player is suspended, the hero can't move
  if (current textbox > -1 || player is suspended) then (exit script)

  # Nor if a menu is up which suspends gameplay.
  # A more complicated menu check could be required if you are using fancy scripted menus that are always visible.
  if(top menu) then(exit script)

  variable(best dir, best time, time)
  best dir := -1
  best time := 999999

  subscript, check key, key, dir, begin
    time := keypress time(key)
    if (key is pressed(key) && time < best time) then (
      best dir := dir
      best time := time
    )
  end

  check key (right key, right)
  check key (left key, left)
  check key (down key, down)
  check key (up key, up)
  return (best dir)
end


# This will return true if hero 0 will move this tick, either because
# they're already moving or because of player input to start a new
# step.
# There are no commands that can tell you that directly: you have to
# figure it out by checking keypresses and for obstructions.
# Note: this doesn't handle all edge cases, like multiple NPCs
# on one tile, or NPCs over the edge of the map
script, hero will move, begin
  variable (dir, npc)

  if (hero is walking(0)) then (exit returning (true))

  # Check for player input
  dir := want to move direction
  if (dir == -1) then (exit returning (false)) 

  # If there's a wall in the way, nothing will happen (unless walls are suspended...)
  if (check hero wall(0, dir)) then (exit returning (false))

  # Check for an NPC in the way which you can't step on
  # (this isn't correct either if obstruction is suspended, or other edge cases)
  npc := npc at spot (hero x(0) + dir x(dir), hero y(0) + dir y(dir))
  if (npc && readNPC(npc, NPCstat:activation) <> NPCactivation:stepon) then (exit returning (false))

  # OK, you will start walking in this direction
  return (true)
end


next leader pixel x/y[edit]

The following scripts will try to guess what the position of the leader (hero 0) will be this tick. This is useful if positioning things relative to the hero.

# Guess the direction that the leader will move this tick, or -1 if they won't move.
script, next leader move direction, begin
  if (hero is walking(0)) then (
    return (hero direction(0))
  ) else if (hero will move) then (
    return (want to move direction)
  ) else (
    return (-1)
  )
end

# Guess the position the leader will move to this tick
script, next leader pixel x, begin
  variable(ret, dir)
  ret := hero pixel x
  dir := next leader move direction
  if (dir <> -1) then (
    ret += get hero speed(0) * dirX(dir)
  )
  return (ret)
end

# Guess the position the leader will move to this tick
script, next leader pixel y, begin
  variable(ret, dir)
  ret := hero pixel y
  dir := next leader move direction
  if (dir <> -1) then (
    ret += get hero speed(0) * dirY(dir)
  )
  return (ret)
end

next camera pixel x/y[edit]

This builds on top of the previous scripts to predict what the location of the camera will be this tick. This script is used by Scripts:Fake Parallax. Call calculate next camera pixel xy before reading the next camera pixel x or next camera pixel y global variables.

The following are supported:

  • camera follows hero(0)
  • pan camera
  • focus camera
  • put camera
  • Map Edge Mode: 'Crop'

The following are not supported:

  • camera follows hero(x) for heroes 1, 2 or 3
  • camera follows npc
  • camera follows slice
  • Map Edge Mode: 'Wrap' or 'Use default tile'
global variable(1, next camera pixel x)
global variable(2, next camera pixel y)

# Updates the values of the "next camera pixel x/y" global variables.
# Camera following NPCs or slices are not supported!
script, calculate next camera pixel xy, begin
  variable(destx, desty, diff, cam dir, cam speed)
  variable(mapw, maph, screenw, screenh)
  screenw := slice width(sprite layer)
  screenh := slice height(sprite layer)
  mapw := map width * 20
  maph := map height * 20

  next camera pixel x := camera pixel x
  next camera pixel y := camera pixel y
  # Check value of gen(genCameraMode)
  if (read general(45) == 0) then (   # herocam (camera following hero)
    # Offset from the top-left of the hero sprite to the topleft of the screen
    next camera pixel x := next leader pixel x -- (screenw -- 20) / 2
    next camera pixel y := next leader pixel y -- (screenh -- 20) / 2
  ) else if (read general(45) == 2) then (  #pancam
    cam dir := read general(46)
    cam speed := read general(48)
    next camera pixel x += dirX(cam dir) * cam speed
    next camera pixel y += dirY(cam dir) * cam speed
  ) else if (read general(45) == 3) then (  #focuscam
    destx := read general(46)
    desty := read general(47)
    cam speed := read general(48)
    diff := destx -- camera pixel x
    if (abs(diff) <= cam speed) then (
      next camera pixel x := dest x
    ) else (
      next camera pixel x += sign(diff) * cam speed
    )
    diff := desty -- camera pixel y
    if (abs(diff) <= cam speed) then (
      next camera pixel y := dest y
    ) else (
      next camera pixel y += sign(diff) * cam speed
    )
  )

  # Crop to map edge
  if (next camera pixel x < 0) then (next camera pixel x := 0)
  if (next camera pixel x > mapw -- screenw) then (next camera pixel x := mapw -- screenw)
  if (next camera pixel y < 0) then (next camera pixel y := 0)
  if (next camera pixel y > maph -- screenh) then (next camera pixel y := maph -- screenh)
end