Reference
  Util\System.txt
  Util\CommonDialog.txt
  Util\Party.txt
  Util\Status.txt
  Util\Color.txt
  Util\VisualEffect.txt
  Util\Input.txt
  Area\Camp.txt
  Util\Audio.txt
End Reference

Import StdUtilLib
  Math = MathUtil
End Import

Constant Direction
  Down  = 0
  Up    = 1
  Right = 2
  Left  = 3
  None  = 255
End Constant

Constant ActorMotion
  Default = "Material"
  Down  = "Down"
  Up    = "Up"
  Right = "Right"
  Left  = "Left"
End Constant

Constant MovingType
  Stopped = 0
  Random = 1
End Constant

Procedure ExitCurrentArea()
  Quit()
End Procedure

Procedure NotifyEntered()
  Dim entered_area = GetAreaObject()
  ResetSignal("OutOf" + entered_area)
  SendSignal("In" + entered_area)
End Procedure

Procedure NotifyExiting()
  Dim exiting_area = GetAreaObject()
  ResetSignal("In" + exiting_area)
  SendSignal("OutOf" + exiting_area)
End Procedure

Procedure GatherAllMembers()
  Dim pm = GetPrimaryActor()
  If pm <> Nothing Then
    Dim members = GetPartyMembers()
    For i = 1 To members.Count
      members[i].Area = pm.Area
      members[i].X = pm.X
      members[i].Y = pm.Y
      members[i].Z = pm.Z
      members[i].Motion = pm.Motion
    Next
  End If
End Procedure

Procedure MoveView(x, y, t) 'Must call LinkView() when finish moving.

  Dim vc = GetViewCenter()  
  Dim xx = x * 32L
  Dim yy = y * 32L
  Dim tt = t * 10000L
  Dim dt = 0L
  Dim t0 = GetClock()
  
  Do While dt < tt
    SetViewCenter(vc.X + xx * dt / tt, vc.Y + yy * dt / tt)
    Sleep(0)
    dt = GetClock() - t0
  Loop
  SetViewCenter(vc.X + xx, vc.Y + yy)
  
End Procedure

Procedure TryWalk(who, vec, z)

  Dim target = CreateList()
  Dim shiftX = CreateList()
  Dim shiftY = CreateList()
  Dim targetZ = CreateList()

  Dim sx = 0
  Dim sy = 0
  target.Add(who)
  If vec = Direction.Down Then
    sy = 32
    who.Motion = ActorMotion.Down
  ElseIf vec = Direction.Up Then
    sy = -32
    who.Motion = ActorMotion.Up
  ElseIf vec = Direction.Right Then
    sx = 32
    who.Motion = ActorMotion.Right
  ElseIf vec = Direction.Left Then
    sx = -32
    who.Motion = ActorMotion.Left
  End If
  sy += ((who.Z - z) / 5) * 16
  shiftX.Add(sx)
  shiftY.Add(sy)
  targetZ.Add(z)

  Dim members = GetPartyMembers()
  If members.Count > 0 AndAlso who = members[1] Then
    For i = 2 To members.Count
      Dim front = members[i - 1]
      Dim back = members[i]
      sx = 0
      sy = 0
      If front.X < back.X Then
        target.Add(back)
        sx = -32
        back.Motion = ActorMotion.Left
      ElseIf front.X > back.X Then
        target.Add(back)
        sx = 32
        back.Motion = ActorMotion.Right
      ElseIf front.Y < back.Y Then
        target.Add(back)
        sy = -32
        back.Motion = ActorMotion.Up
      ElseIf front.Y > back.Y Then
        target.Add(back)
        sy = 32
        back.Motion = ActorMotion.Down
      End If
      sy += ((back.Z - front.Z) / 5) * 16
      If sx <> 0 OrElse sy <> 0 Then
        shiftX.Add(sx)
        shiftY.Add(sy)
        targetZ.Add(front.Z)
      End If
    Next
  End If

  Dim tt = 1666666L 'taking times(100ns) for a step
  Dim dt = 0L
  Dim t0 = GetClock()

  Do
    For i = 1 To target.Count
      Dim tg = target[i]
      tg.OffsetX = shiftX[i] * dt / tt
      tg.OffsetY = shiftY[i] * dt / tt
      If dt < tt / 2L Then
        tg.Frame = 1
      Else
        tg.Frame = 0
      End If
    Next
    Sleep(0)
    dt = GetClock() - t0
  Loop While dt < tt

  For i = 1 To target.Count
    Dim tg = target[i]
    tg.OffsetX = 0
    tg.OffsetY = 0
    tg.Frame = 0
    tg.X += Math.Sign(shiftX[i])
    tg.Y += Math.Sign(shiftY[i] - ((tg.Z - targetZ[i]) / 5) * 16)
    tg.Z = targetZ[i]
  Next

End Procedure

Procedure OnException(message, call_stack)
  TraceException(message, call_stack)
  RaiseEvent("AreaProcessTerminated")
End Procedure

Procedure RegisterCommonEventHandlers()
  SetExceptionHandler(OnException)
  RegisterEventHandler("ExitCurrentArea", ExitCurrentArea)
  RegisterEventHandler("HAVE_TO_GO", BeginOutsideWarp)
End Procedure

Procedure ProcessMoving_Waiting(who, timeout)
  Sleep(timeout)
  who.MovingThread = Nothing
End Procedure

Procedure ProcessMoving_Random(who, vec, z)
  TryWalk(who, vec, z)
  If Not MovingType.Stopped Then
    who.MovingThread = RunThread(ProcessMoving_Waiting, who, 1000)
  Else
    who.MovingThread = Nothing
  End If
End Procedure

Procedure ProcessActorMoving()
  Dim actors = GetActors()
  For i = 1 To actors.Count
    Dim who = actors[i]
    Dim mt = MovingType.Stopped
    If TryGetActorData(who, "MovingType", mt) = True AndAlso who.MovingThread = Nothing Then
      If mt = MovingType.Stopped Then
        who.MovingThread = Nothing
      ElseIf mt = MovingType.Random Then
        Dim vec = Math.GetRandom(0, 4)
        Dim x = who.X
        Dim y = who.Y
        If vec = Direction.Down Then
          y += 1
          who.Motion = ActorMotion.Down
        ElseIf vec = Direction.Up Then
          y -= 1
          who.Motion = ActorMotion.Up
        ElseIf vec = Direction.Right Then
          x += 1
          who.Motion = ActorMotion.Right
        ElseIf vec = Direction.Left Then
          x -= 1
          who.Motion = ActorMotion.Left
        End If
        Dim ci = TestCollision(who, x, y)
        If ci[1] = False AndAlso IsInZone(who.Zone, x, y, ci[3]) Then
          who.MovingThread = RunThread(ProcessMoving_Random, who, vec, ci[3])
        Else
          who.MovingThread = RunThread(ProcessMoving_Waiting, who, 1000)
        End If
      End If
    End If
  Next
End Procedure

Procedure LetActorWalk(who, vec)
  Dim x = who.X
  Dim y = who.Y
  If vec = Direction.Down Then
    y += 1
  ElseIf vec = Direction.Up Then
    y -= 1
  ElseIf vec = Direction.Right Then
    x += 1
  ElseIf vec = Direction.Left Then
    x -= 1
  End If
  Dim ci = TestCollision(who, x, y)
  TryWalk(who, vec, ci[3])
End Procedure

Procedure LetActorTurn(who, vec)
  If vec = Direction.Down Then
    who.Motion = ActorMotion.Down
  ElseIf vec = Direction.Up Then
    who.Motion = ActorMotion.Up
  ElseIf vec = Direction.Right Then
    who.Motion = ActorMotion.Right
  ElseIf vec = Direction.Left Then
    who.Motion = ActorMotion.Left
  End If
  Sleep(0)
End Procedure

Procedure MotionToDirection(m)
  If m = ActorMotion.Down Then Return Direction.Down
  If m = ActorMotion.Up Then Return Direction.Up
  If m = ActorMotion.Right Then Return Direction.Right
  If m = ActorMotion.Left Then Return Direction.Left
  Return Direction.None
End Procedure

Procedure DirectionToMotion(d)
  If d = Direction.Down Then Return ActorMotion.Down
  If d = Direction.Up Then Return ActorMotion.Up
  If d = Direction.Right Then Return ActorMotion.Right
  If d = Direction.Left Then Return ActorMotion.Left
  Return ActorMotion.Default
End Procedure

Procedure ProcessInput()
  
  ProcessActorMoving()
  
  If Not WaitForSignal("PLAYERS_CONTROL", 0) Then
    Sleep(0)
    Return
  End If

  Dim pa = GetPrimaryActor()
  Dim px = pa.X
  Dim py = pa.Y

  Dim curr = GetInputState()
  Dim diff = (GetPreviousInputState() Xor curr) And curr

  Dim vec = Direction.Down

  Dim down_now = TestInput(curr, Buttons.Down)
  Dim up_now = TestInput(curr, Buttons.Up)
  Dim right_now = TestInput(curr, Buttons.Right)
  Dim left_now = TestInput(curr, Buttons.Left)

  If TestInput(diff, Buttons.A) Then
    Dim aroundActors = GetAroundActors(pa)
    For i = 1 To aroundActors.Count
      Dim anActor = aroundActors[i]
      Dim ax = anActor.X
      Dim ay = anActor.Y
      Dim raise_contact_event = False
      If pa.Motion = ActorMotion.Down Then
        If ax = px AndAlso ay = py + 1 Then
          If anActor.Material.Turnable Then anActor.Motion = ActorMotion.Up
          raise_contact_event = True
        End If
      ElseIf pa.Motion = ActorMotion.Up Then
        If ax = px AndAlso ay = py - 1 Then
          If anActor.Material.Turnable Then anActor.Motion = ActorMotion.Down
          raise_contact_event = True
        End If
      ElseIf pa.Motion = ActorMotion.Right Then
        If ax = px + 1 AndAlso ay = py Then
          If anActor.Material.Turnable Then anActor.Motion = ActorMotion.Left
          raise_contact_event = True
        End If
      ElseIf pa.Motion = ActorMotion.Left Then
        If ax = px - 1 AndAlso ay = py Then
          If anActor.Material.Turnable Then anActor.Motion = ActorMotion.Right
          raise_contact_event = True
        End If
      End If
      If raise_contact_event OrElse (ax = px AndAlso ay = py) Then
        RaiseEvent(anActor + "Contact", anActor)
      End If
    Next
    Sleep(0)
    Return
  ElseIf TestInput(diff, Buttons.X) Then
    DoCamp()
    Return
  ElseIf right_now AndAlso Not (down_now OrElse up_now) Then
    vec = Direction.Right
    pa.Motion = ActorMotion.Right
    px += 1
  ElseIf left_now AndAlso Not (down_now OrElse up_now) Then
    vec = Direction.Left
    pa.Motion = ActorMotion.Left
    px -= 1
  ElseIf down_now Then
    vec = Direction.Down
    pa.Motion = ActorMotion.Down
    py += 1
  ElseIf up_now Then
    vec = Direction.Up
    pa.Motion = ActorMotion.Up
    py -= 1
  Else
    Sleep(0)
    Return
  End If

  Dim canGo = False
  Dim ci = TestCollision(pa, px, py)
  If Not ([RVII].Debugging AndAlso TestInput(curr, Buttons.B)) Then
    If ci[1] = False Then
      canGo = True
    Else
      Dim members = GetPartyMembers()
      ci = TestCollision(members[1], px, py)
      If ci[1] = False Then
        GetOff()
        pa = GetPrimaryActor()
        canGo = True
      End If
    End If
  Else
    canGo = True
  End If

  If canGo Then
  
    SetGameInfo("NumOfSteps", GetGameInfo("NumOfSteps") + 1)

    Dim enter_or_leave_raised = False
    
    Dim prev_entered = GetEnteredBoundsList()
    TryWalk(pa, vec, ci[3])
    Dim curr_entered = GetEnteredBoundsList()
    For i = 1 To prev_entered.Count
      Dim prev_bounds = prev_entered[i]
      If Not curr_entered.Contains(prev_bounds) Then
        enter_or_leave_raised = enter_or_leave_raised Or _
          RaiseEvent(prev_bounds + "Leave", prev_bounds)
      End If
    Next i
    For i = 1 To curr_entered.Count
      Dim curr_bounds = curr_entered[i]
      If Not prev_entered.Contains(curr_bounds) Then
        enter_or_leave_raised = enter_or_leave_raised Or _
          RaiseEvent(curr_bounds + "Enter", curr_bounds)
      End If
    Next i
    
    'When Enter or Leave event raised, Step event don't raise.
    'This behavior is to avoid the problem "player exiting from area" and
    '"player step in zone and entering battle" occurred at the same time.

    If ci[2] = [Ship] Then
      GetOn([Ship])
    End If
    If Not enter_or_leave_raised Then
      Dim geo = GetGroundMaterial()
      If geo <> 0 Then
        For i = 1 To curr_entered.Count
          RaiseEvent(curr_entered[i] + "Step", geo)
        Next
      End If
    End If
    Return
  Else
    Dim thereActor = ci[2]
    If thereActor <> Nothing Then
      If RaiseEvent(thereActor + "Hit", thereActor) Then Return
    End If
  End If
  Sleep(0)

End Procedure

Procedure GetOn(the_vehicle)
  Dim members = GetPartyMembers()
  For i = 1 To members.Count
    members[i].Visible = False
  Next
  SetPrimaryActor(the_vehicle)
  SetGameInfo("Primary", GetPrimaryActor())
End Procedure

Procedure GetOff()
  GatherAllMembers()
  Dim members = GetPartyMembers()
  For i = 1 To members.Count
    members[i].Visible = True
  Next
  SetPrimaryActor(members[1])
  SetGameInfo("Primary", GetPrimaryActor())
End Procedure

Procedure BeginOutsideWarp(nextArea, nextPoint)
  ResetSignal("PLAYERS_CONTROL")
  RaiseEvent("OutsideWarp", GetAreaObject(), nextArea, nextPoint, True)
End Procedure

Procedure BeginOutsideWarpNoFX(nextArea, nextPoint)
  RaiseEvent("OutsideWarpNoFX", GetAreaObject(), nextArea, nextPoint)
End Procedure

Dim g_AreaZones = CreateList()
Dim g_AreaZoneData = CreateDictionary()

Procedure AddAreaZone(area_zone, bgtex)
  g_AreaZones.Add(area_zone)
  g_AreaZoneData.Add(area_zone, {bgtex})
End Procedure

Procedure DoInsideWarp(next_point, vec, with_fading)
  Dim pm = GetPrimaryActor()
  Dim azx = next_point_zone.X
  Dim azy = next_point_zone.Y
  Dim azz = next_point_zone.Z
  Dim next_point_zone = GetAreaObject(next_point)
  If next_point_zone <> Nothing Then
    azx = next_point_zone.X
    azy = next_point_zone.Y
    azz = next_point_zone.Z
  Else
    azx = pm.X
    azy = pm.Y
    azz = pm.Z
  End If
  Dim az = Nothing
  For i = 1 To g_AreaZones.Count
    If IsInZone(g_AreaZones[i], azx, azy, azz) Then
      az = g_AreaZones[i]
      Exit For
    End If
  Next
  If with_fading Then
    FadeIn(0, 0, 0, 500)
    Sleep(500)
  End If
  If az <> Nothing Then
    ChangeVisibility(az.X, az.Y, az.Z, az.X + az.Width - 1, az.Y + az.Height - 1, az.Z + az.Depth - 1)
    ChangeBGTex(g_AreaZoneData[az][1])
  Else
    ChangeVisibility()
    ChangeBGTex()
  End If
  pm.X = azx
  pm.Y = azy
  pm.Z = azz
  If vec = Direction.Down Then
    pm.Motion = ActorMotion.Down
  ElseIf vec = Direction.Up Then
    pm.Motion = ActorMotion.Up
  ElseIf vec = Direction.Right Then
    pm.Motion = ActorMotion.Right
  ElseIf vec = Direction.Left Then
    pm.Motion = ActorMotion.Left
  End If
  GatherAllMembers()
  If with_fading Then
    FadeOut(0, 0, 0, 500)
  End If
End Procedure

Procedure DoStairWarp(next_point, vec, with_fading)
  PlayAudio(Sound.Stair)
  DoInsideWarp(next_point, vec, with_fading)
End Procedure

Procedure DoFallingWarp(the_bounds, next_point, vec, with_fading)
  Dim hole_zone = GetZone(the_bounds)
  Dim ac = AddActor("HL", hole_zone.X, hole_zone.Y, hole_zone.Z, [A_Hole], ActorMotion.Default)
  Sleep(500)
  'DoMsg([TheHero].Name, "「うわあああああ！」")
  PlayAudio(Sound.Falling)
  DoInsideWarp(next_point, vec, with_fading)
  RemoveActor(ac)
End Procedure

Procedure EndOfTheWorld()
  'Quit()
  ResetSignal("PLAYERS_CONTROL")
  RaiseEvent("ResetTheWorld")
End Procedure

Procedure GetPartyLevel()
  Dim members = GetPartyMembers()
  If members.Count > 0 Then
    Dim sum = 0
    For i = 1 To members.Count
      Dim who = members[i]
      sum += who.PPLevel
      sum += who.MPLevel
    Next
    Return sum / members.Count
  Else
    Return 0
  End If
End Procedure

Dim g_StepsForEncountering = 0
Dim g_MaterialStepsMap = CreateDictionary()

Procedure SetStepsOfMaterial(mat, steps)
  g_MaterialStepsMap[mat] = steps
End Procedure

Procedure TestEncountering(mat)
  If g_MaterialStepsMap.Contains(mat) Then
    Dim steps = g_MaterialStepsMap[mat]
    If g_StepsForEncountering <= steps Then
      Return True
    Else
      g_StepsForEncountering -= steps
    End If
  End If
  Return False
End Procedure

Procedure ResetStepsForEncountering()
  Dim x = 0
  For i = 1 To (600 - 1) * 2
    x += Math.GetRandom(0, 2)
  Next
  g_StepsForEncountering = x + 1
End Procedure

Procedure DoNormalBattle(enemy_parties)
  If [RVII].Debugging AndAlso TestFlag("Debug_NoBattle") Then Return True
  BlinkScreen()
  PauseBGM()
  ChangeBGM(Music.Battle2)
  Dim battle_result = 0
  Dim bp = BeginProcess("Area\Battle.txt", True, _
    enemy_parties[Math.GetRandom(0, enemy_parties.Count) + 1])
  Do While Not WaitForCompletion(bp, battle_result)
    Sleep(100)
  Loop
  If battle_result <> 2 Then
    ResumeBGM()
    If TestFlag("Rabro_2") Then
      [TheHero].MP = Math.Min([TheHero].MP + 3, [TheHero].MaxMP)
    End If
  Else
    EndOfTheWorld()
  End If
  Return battle_result <> 2
End Procedure

Procedure DoBossBattle(boss_party)
  If [RVII].Debugging AndAlso TestFlag("Debug_NoBattle") Then Return True
  BlinkScreen()
  PauseBGM()
  ChangeBGM(Music.Battle3)
  Dim battle_result = 0
  Dim bp = BeginProcess("Area\Battle.txt", False, boss_party)
  Do While Not WaitForCompletion(bp, battle_result)
    Sleep(100)
  Loop
  ResumeBGM()
  Return battle_result <> 2
End Procedure

Constant BoxContent
  Empty = 0
  Tool = 1
  Money = 2
  Enemy = 3
End Constant

Procedure AddBox(name, x, y, z, content_type, content, ch)
  Dim tb = Nothing
  If Not TestFlag(name) Then
    tb = AddActor(name, x, y, z, [A_TBClosed], ActorMotion.Default)
    SetActorData(tb, "Type", content_type)
    SetActorData(tb, "Content", content)
  Else
    tb = AddActor(name, x, y, z, [A_TBOpened], ActorMotion.Default)
    SetActorData(tb, "Type", BoxContent.Empty)
    SetActorData(tb, "Content", Nothing)
  End If
  If ch = Nothing Then
    RegisterEventHandler(name + "Contact", Box_Contact_StdHandler)
  Else
    RegisterEventHandler(name + "Contact", ch)
  End If
  Return tb
End Procedure

Procedure Box_Contact_StdHandler(tb)
  If Not TestFlag(tb) Then
    SetFlag(tb)
    PlayAudio(Sound.Box)
    Sleep(200)
    tb.Material = [A_TBOpened]
    Sleep(300)
    Dim content_type = tb.Type
    Dim content = tb.Content
    If content_type = BoxContent.Tool Then
      GiveUsTool(content)
      DoMsg(content.Name + "をてにいれた")
    ElseIf content_type = BoxContent.Money Then
      ReceiveMoney(content)
      DoMsg(MoneyStr(content) + "てにいれた")
    ElseIf content_type = BoxContent.Enemy Then
      DoNormalBattle(content)
    Else
      DoMsg("しかし　なにもなかった")
    End If
  Else
    DoMsg("すでに　あけられている")
  End If
End Procedure

Procedure SetZoneOfTown(area_width, area_height, left, top, right, bottom, exit_handler)
  AddAreaZone(AddZone("WHOLE_OF_TOWN", 0, 0, 0, area_width - 1, area_height - 1, 99), 2)
  AddZone("AreaRegion", left, top, 0, right, bottom, 99)
  ChangeVisibility(0, 0, 0, area_width - 1, area_height - 1, 99)
  ChangeBGTex(2)
  AddZone("OutOfAreaL", left - 1, top, 0, left - 1, bottom, 99)
  RegisterEventHandler("OutOfAreaLEnter", exit_handler)
  AddZone("OutOfAreaT", left, top - 1, 0, right, top - 1, 99)
  RegisterEventHandler("OutOfAreaTEnter", exit_handler)
  AddZone("OutOfAreaR", right + 1, top, 0, right + 1, bottom, 99)
  RegisterEventHandler("OutOfAreaREnter", exit_handler)
  AddZone("OutOfAreaB", left, bottom + 1, 0, right, bottom + 1, 99)
  RegisterEventHandler("OutOfAreaBEnter", exit_handler)
End Procedure

Procedure SetZoneOfCastle(area_width, area_height, left, top, right, bottom, exit_handler)
  AddAreaZone(AddZone("WHOLE_OF_CASTLE", 0, 0, 0, area_width - 1, area_height - 1, 99), 2)
  AddZone("AreaRegion", left, top, 0, right, bottom, 99)
  ChangeVisibility(0, 0, 0, area_width - 1, area_height - 1, 99)
  ChangeBGTex(2)
  AddZone("OutOfAreaL", left - 1, top, 0, left - 1, bottom, 99)
  RegisterEventHandler("OutOfAreaLEnter", exit_handler)
  AddZone("OutOfAreaT", left, top - 1, 0, right, top - 1, 99)
  RegisterEventHandler("OutOfAreaTEnter", exit_handler)
  AddZone("OutOfAreaR", right + 1, top, 0, right + 1, bottom, 99)
  RegisterEventHandler("OutOfAreaREnter", exit_handler)
  AddZone("OutOfAreaB", left, bottom + 1, 0, right, bottom + 1, 99)
  RegisterEventHandler("OutOfAreaBEnter", exit_handler)
End Procedure

Procedure SetEntrance(x, y, z, vec)
  AddZone("Entrance", x, y, z)
  Return vec
End Procedure

Procedure SetEntranceEx(when_down, when_up, when_right, when_left)
  Dim vec = MotionToDirection(GetPrimaryActor().Motion)
  If vec = Direction.Down Then
    AddZone("Entrance", when_down[1], when_down[2], when_down[3])
  ElseIf vec = Direction.Up Then
    AddZone("Entrance", when_up[1], when_up[2], when_up[3])
  ElseIf vec = Direction.Right Then
    AddZone("Entrance", when_right[1], when_right[2], when_right[3])
  ElseIf vec = Direction.Left Then
    AddZone("Entrance", when_left[1], when_left[2], when_left[3])
  End If
  Return vec
End Procedure

Procedure PutAreaNameLabel()
  Dim ss = GetScreenSize()
  PutLabel(ss.X * 2 / 3, ss.Y * 3 / 4, [F_MSG], Color.LightGray, _
    GetAreaObject().Name, 500, 1500, 1000)
End Procedure

Procedure AddActor_MTRandom(name, x, y, z, a, ch)
  Dim ac = AddActor(name, x, y, z, a, ActorMotion.Down)
  SetActorData(ac, "MovingThread", Nothing)
  SetActorData(ac, "MovingType", MovingType.Random)
  SetActorData(ac, "Zone", GetZone("AreaRegion"))
  If ch <> Nothing Then RegisterEventHandler(name + "Contact", ch)
  Return ac
End Procedure

Procedure AddActor_MTZonedRandom(name, x, y, z, x0, y0, z0, x1, y1, z1, a, ch)
  Dim ac = AddActor(name, x, y, z, a, ActorMotion.Down)
  SetActorData(ac, "MovingThread", Nothing)
  SetActorData(ac, "MovingType", MovingType.Random)
  SetActorData(ac, "Zone", AddZone(ac.Tag + "Zone", x0, y0, z0, x1, y1, z1))
  If ch <> Nothing Then RegisterEventHandler(name + "Contact", ch)
  Return ac
End Procedure

Procedure AddActor_MTStopped(name, x, y, z, a, v, ch)
  Dim ac = AddActor(name, x, y, z, a, v)
  SetActorData(ac, "MovingThread", Nothing)
  SetActorData(ac, "MovingType", MovingType.Stopped)
  If ch <> Nothing Then RegisterEventHandler(name + "Contact", ch)
  Return ac
End Procedure

Procedure AddStaticActor(name, x, y, z, a, ch)
  Dim ac = AddActor(name, x, y, z, a, ActorMotion.Default)
  SetActorData(ac, "MovingThread", Nothing)
  SetActorData(ac, "MovingType", MovingType.Stopped)
  If ch <> Nothing Then RegisterEventHandler(name + "Contact", ch)
  Return ac
End Procedure
