Reference
  Util\CommonDialog.txt
  Util\Color.txt
  Util\FileOperation.txt
  Util\VisualEffect.txt
  Util\System.txt
  Util\Party.txt
  Area\Util.txt
  Util\Audio.txt
End Reference

Dim shaker_thread = Nothing

Procedure ShakeProc()
  Dim quake_sound = PlayAudio(Sound.Quake)
  Dim s = {2, 1, 2, 4, 3, 1, 0, 1}
  Dim xi = 1
  Dim yi = 1
  Do
    ShiftView(s[xi] - 2, (s[yi] - 2) * 2)
    If xi < 8 Then xi += 1 Else xi = 1
    If yi < 6 Then yi += 3 Else yi -= 5
  Loop While Not WaitForSignal("StopShaking", 50)
  ShiftView(0, 0)
  quake_sound.Stop(0)
End Procedure

Procedure DoStartShake()
  If shaker_thread = Nothing Then
    shaker_thread = RunThread(ShakeProc)
  End If
End Procedure

Procedure DoStopShake()
  If shaker_thread <> Nothing Then
    SendSignal("StopShaking")
    Do While Not WaitForCompletion(shaker_thread)
      Sleep(10)
    Loop
    shaker_thread = Nothing
    ResetSignal("StopShaking")
  End If
End Procedure

Dim bgm_cue = Nothing
Dim paused_cue = Nothing

Procedure DoChangeBGM(cue_name)
  If bgm_cue <> Nothing Then
    bgm_cue.Stop(0)
    bgm_cue = Nothing
  End If
  If cue_name <> Nothing Then
    bgm_cue = PlayAudio(cue_name)
  End If
End Procedure

Procedure DoPauseBGM()
  If paused_cue <> Nothing Then
    paused_cue.Stop(0)
    paused_cue = Nothing
  End If
  If bgm_cue <> Nothing Then
    bgm_cue.Pause()
    paused_cue = bgm_cue
    bgm_cue = Nothing
  End If
End Procedure

Procedure DoResumeBGM()
  If bgm_cue <> Nothing Then
    bgm_cue.Stop(0)
    bgm_cue = Nothing
  End If
  If paused_cue <> Nothing Then
    bgm_cue = paused_cue
    paused_cue = Nothing
    bgm_cue.Resume()
  End If
End Procedure

Procedure DoOutsideWarp(currentArea, nextArea, nextPoint, restore_control)
  
  If restore_control Then ResetSignal("PLAYERS_CONTROL")
  FadeIn(255, 255, 255, 1000)
  Sleep(1000)
  
  Do
    Dim script_error = PreloadScript("Area\" + nextArea + "\Script.txt")
    If script_error <> Nothing Then
      For i = 1 To script_error.Count
        Trace(script_error[i])
      Next
      If DoYesNoMsg(nextArea.Name + "のプログラムに", _
        "エラーがあるため実行できません", _
        "詳細はログを確認してください", _
        "もう一度　実行を試みますか？") Then
        Continue Do
      Else
        FadeOut(255, 255, 255, 0)
        If restore_control Then SendSignal("PLAYERS_CONTROL")
        Return
      End If
    Else
      Exit Do
    End If
  Loop
  
  If currentArea <> Nothing Then
    RaiseEvent("ExitCurrentArea")
    WaitForSignal("OutOf" + currentArea)
  End If
  GetPrimaryActor().Area = nextArea
  BeginAreaProcess(nextArea, "Area\" + nextArea + "\Script.txt", nextPoint)
  WaitForSignal("In" + nextArea)
  FadeOut(255, 255, 255, 1000)
  If restore_control Then SendSignal("PLAYERS_CONTROL")
End Procedure

Procedure DoOutsideWarpNoFX(currentArea, nextArea, nextPoint)
  If currentArea <> Nothing Then
    RaiseEvent("ExitCurrentArea")
    WaitForSignal("OutOf" + currentArea)
  End If
  GetPrimaryActor().Area = nextArea
  BeginAreaProcess(nextArea, "Area\" + nextArea + "\Script.txt", nextPoint)
  WaitForSignal("In" + nextArea)
End Procedure

Procedure MyExceptionHandler(message, call_stack)
  TraceException(message, call_stack)
  DoMsg("プログラムで重大なエラーが発生しました。", "詳細はログを確認してください。")
End Procedure

Procedure ExceptionHandler()
  If DoYesNoMsg("エリア内でエラーが発生しました。", "詳細はログを確認してください。", "実行を続けますか？") = True Then
    ClearScriptCache()
    DoOutsideWarp(Nothing, GetPrimaryActor().Area, Nothing, True)
  Else
    Quit()
  End If
End Procedure

Dim global_timer_thread = Nothing

Procedure TimeCountProc()
  Dim last_tick = GetClock()
  Dim last_time = GetGameInfo("ElapsedTime")
  Do
    Dim tick = GetClock()
    last_time += tick - last_tick
    SetGameInfo("ElapsedTime", last_time)
    last_tick = tick
  Loop While Not WaitForSignal("StopGlobalTimer", 10) 
End Procedure

Procedure ResetTheWorld()
  Dim current_area = GetPrimaryActor().Area
  If current_area <> Nothing Then
    RaiseEvent("ExitCurrentArea")
    WaitForSignal("OutOf" + current_area)
  End If
  If paused_cue <> Nothing Then
    paused_cue.Stop(0)
    paused_cue = Nothing
  End If
  If bgm_cue <> Nothing Then
    bgm_cue.Stop(0)
    bgm_cue = Nothing
  End If
  DoStopShake()
  If global_timer_thread <> Nothing Then
    SendSignal("StopGlobalTimer")
    WaitForCompletion(global_timer_thread)
    global_timer_thread = Nothing
    ResetSignal("StopGlobalTimer")
  End If
  Sleep(1000)
  GetPrimaryActor().Area = Nothing
  SetPrimaryActor(Nothing)
  FadeOutProc(0, 0, 0, 0)
  Quit()
End Procedure

Procedure Main()

  Dim ss = GetScreenSize()
  
  MapButtonToInput(1, ButtonIndex.A)
  MapButtonToInput(2, ButtonIndex.B)
  MapButtonToInput(3, ButtonIndex.X)
  MapButtonToInput(4, ButtonIndex.Y)
  MapButtonToInput(41, ButtonIndex.Left)
  MapButtonToInput(42, ButtonIndex.Right)
  MapButtonToInput(43, ButtonIndex.Up)
  MapButtonToInput(44, ButtonIndex.Down)
  MapKeyToButton(86, 1)
  MapKeyToButton(67, 2)
  MapKeyToButton(88, 3)
  MapKeyToButton(90, 4)
  MapKeyToButton(37, 41)
  MapKeyToButton(39, 42)
  MapKeyToButton(38, 43)
  MapKeyToButton(40, 44)
  SetInputInterval(ButtonIndex.Left, 30, 6)
  SetInputInterval(ButtonIndex.Right, 30, 6)
  SetInputInterval(ButtonIndex.Up, 30, 6)
  SetInputInterval(ButtonIndex.Down, 30, 6)
  
  SetExceptionHandler(MyExceptionHandler)
  RegisterEventHandler("EndOfTheWorld", EndOfTheWorld)
  RegisterEventHandler("ResetTheWorld", ResetTheWorld)
  RegisterEventHandler("OutsideWarp", DoOutsideWarp)
  RegisterEventHandler("OutsideWarpNoFX", DoOutsideWarpNoFX)
  RegisterEventHandler("ChangeBGM", DoChangeBGM)
  RegisterEventHandler("PauseBGM", DoPauseBGM)
  RegisterEventHandler("ResumeBGM", DoResumeBGM)
  RegisterEventHandler("StartShake", DoStartShake)
  RegisterEventHandler("StopShake", DoStopShake)
  RegisterEventHandler("AreaProcessTerminated", ExceptionHandler)
  
  PutLabel((ss.X - 228) / 2, (ss.Y - 20) / 2, [F_MSG], Color.White, _
    "M O R T A L   R O A R", 1000, 3000, 2000)

  Dim currentClock = GetClock()

  LoadGameData(0)

  Dim elapsedClock = (GetClock() - currentClock) / 10000
  If elapsedClock < 6000 Then Sleep(6000 - elapsedClock)
  
  PutLabel(ss.X - 418, ss.Y - 30, [F_MSG], Color.Pink, _
    "We are looking for something real!", 1000, 3000, 2000)

  Dim textures = GetElements("Texture")
  For i = 1 To textures.Count
    LoadTexture(textures[i])
  Next

  Dim wave_banks = GetElements("WaveBank")
  For i = 1 To wave_banks.Count
    LoadWaveBank(wave_banks[i])
  Next
  
  Sleep(0)
  
  SetVolume("Music", 50)
  SetVolume("Default", 50)
  DoChangeBGM(Music.Opening)

  Do
    Dim hMenu = CreateDataSlotMenuForLoad(80, 80, 480, 280, Nothing, Nothing, _
      "ロードするスロットをえらんでください", 1)
    Dim index = ProcessMenu(hMenu)
    DestroyControl(hMenu)
    If index > 1 AndAlso IsDataSlotUsed(index - 1) Then
      LoadGameData(index - 1)
      global_timer_thread = RunThread(TimeCountProc)
      SetPrimaryActor(GetGameInfo("Primary"))
      SetAudioVolume(AudioCategory.Sound, GetAudioVolume(AudioCategory.Sound))
      SetAudioVolume(AudioCategory.Music, GetAudioVolume(AudioCategory.Music))
      DoOutsideWarp(Nothing, GetPrimaryActor().Area, Nothing, True)
      Idle()
      LoadGameData(0)
    ElseIf index <> 0 Then
      DoMsg("主人公の名前を入力してください")
      Dim theName = [TheHero].Name
      Do
        theName = InputKatakana(theName, 8)
      Loop While theName <> Nothing AndAlso Not DoYesNoMsg(theName + "でよろしいですか？")
      If theName <> Nothing Then
        [TheHero].Name = theName
        [TheHero].Area = [Pramarl]
        [TheHero].X = 31
        [TheHero].Y = 59
        [TheHero].Z = 0
        [TheHero].Motion = ActorMotion.Up
        [TheHero].Visible = True
        [TheHero].OrderInClass = 1
        [TheHero].Weapon = [BronzeSword]
        [TheHero].Armor = [LeatherArmor]
        [TheHero].Shield = [LeatherShield]
        [TheHero].Helmet = [LeatherHelmet]
        Equip([TheHero])
        global_timer_thread = RunThread(TimeCountProc)
        Sleep(1000)
        DoMsg("ラブロの町に住む少年　" + theName + "は", _
          "父の使いで　プラマール城に来ていた")
        SetPrimaryActor(GetGameInfo("Primary"))
        DoOutsideWarp(Nothing, GetPrimaryActor().Area, "OpeningStart", True)
        Idle()
        LoadGameData(0)
      End If
    End If
  Loop
  
  DoChangeBGM(Nothing)
  Return 0

End Procedure
