require("lib/york")
require("common")

MissionStates = {
  Initial = 0,
  hasTalkedToAllan = 1,
  spokeWithTuck = 2,
  spokeWithSpy = 3,
  spiedMeeting = 4,
  Won = 5
}

AllanState = {
  Initial = 0,
  HouseIsKnown = 1,
  ReadyToTalk = 2,
  HintToCathedral = 3,
  spokeWithTuck = 4,
  ReadyToTalkAfterTuck = 5,
  LambInCastle = 6
}

TuckState = {
  Initial = 0,
  ReadyToTalk = 1,
  EnoughLegsOfLambs = 2,
  SpyActivated = 3
}

Globals = {
  MissionState = MissionStates.spokeWithSpy,
  AllanStatus = AllanState.Initial,
  TuckStatus = TuckState.Initial,

  LoseByTuckDown = false,
  BeggarNotSavedText = 6,
  NotEnoughLegsOfLamb = false,
  SheriffHasBeenWarned = false,
  AllanLeavesHouse = false,
  hasTalkedToSearchingLady = false,
  hasTalkedToHidingSon = false,
  LadyIsHome = false,
  TuckTriggered = false,
  RequiredLegsOfLamb = 6,
  GivenLegsOfLamb    = 0,

  --unused - to be deleted before publishing
  OfficerCalledSoldiers = false,
}


function Initialize()
  InitializeYork()
  DeactivateSherwoodSigns()

  DeactivateAnimations({
    MiscAnimation.pigeonsWestOfCathedral,
    MiscAnimation.crowNorthWest01,
    MiscAnimation.crowNorthWest02,
    MiscAnimation.crowNorthWest03,
    MiscAnimation.crowSouthWest01,
    MiscAnimation.crowSouthWest02,
  })

  ApplyPatch(GetPatchScript(MiscPatch.outerEastGate))
  ApplyPatch(GetPatchScript(MiscPatch.innerEastGate))
  ApplyPatch(GetPatchScript(MiscPatch.marketStandPixelVert))

  local tuck = GetActor("FriarTuck_6")
  StopActor(tuck)                               -- sofortiges Anhalten
  SetAIState(tuck, AiState.script)    

  StartSequence()
  SequencePlayAnimFreeze(GetActor("CastleTreadWheel"), AnimationAction.sittingToStanding)
  EndSequence()

  DoorLockedButUnlockable(MiscDoor.secretPassageOuter)
  ActivateDoorMouseSector(false, GetDoorScript(MiscDoor.secretPassageOuter))

  AddObjective(0, true)
  AddObjective(1, true)
  AddObjective(13, false) -- side quest find Haslock

  DeactivateActors({
    GetActor("Allan_1")
  })
  


  DeactivateItems({
    GetItem("Apples_10"),
    GetItem("Stones_17"),
    GetItem("Nets_7"),
    GetItem("MedicinalHerbs_19"),
    GetItem("Money_3"),
    GetItem("LegsOfLamb_11"),
    GetItem("LegsOfLamb_18"),
    GetItem("LegsOfLamb_20"),
    GetItem("LegsOfLamb_21"),
    GetItem("LegsOfLamb_22"),
    GetItem("LegsOfLamb_23"),
    GetItem("LegsOfLamb_24"),
    GetItem("Clovers_13"),
    GetItem("Money_5")
  })

  AttachScrollToNPC(GetActor("WomanCivilianFriend_9"), GetScroll("Scroll_23"))
  AttachScrollToNPC(GetActor("Allan_1"), GetScroll("Scroll_1"))

  CustomizeMinimapDisplay(GetActor("Child_10"),0) -- Missing child is invisible on minimap

-- Lock Black Knights to avoid them coming out in case of alarm inside of castle
  LockOnPlace(GetActor("Chevalier_Noir_24"))
  LockOnPlace(GetActor("Chevalier_Noir_25"))


end



function PostInitialize()
  StartSequence()
  SequenceSetZoomLevel(ZoomLevel.default)
  SequenceLockUser()
  Then()
  SequenceDisplayPopupText(0)
  Then()
  SequenceDisplayPopupText(1)
  Then()
  SequenceUnLockUser()
  EndSequence()


-- Lock Door where Chevaliers will hide and get deactivated
  SetDoorLockedPC(GetDoorScript(15), true)
  SetDoorLockedPC(GetDoorScript(16), true)
  SetDoorLockedPC(GetDoorScript(17), true)
  SetDoorLockedPC(GetDoorScript(21), true)    
  SetDoorLockedPC(GetDoorScript(22), true)
  SetDoorLockedPC(GetDoorScript(81), true)
  SetDoorLockedPC(GetDoorScript(82), true)
  SetDoorLockedPC(GetDoorScript(96), true)
  SetDoorUnlockable(GetDoorScript(96), true)
  SetDoorLockedPC(GetDoorScript(118), true)
  SetDoorLockedPC(GetDoorScript(119), true)
  SetDoorLockedPC(GetDoorScript(120), true)
  SetDoorLockedPC(GetDoorScript(121), true)
  SetDoorLockedPC(GetDoorScript(122), true)

  SetDoorLockedNPCVillain(GetDoorScript(20), true)
end



function Timer(secondsPassed)
  ActivateAllan()
  ActivateTuck()
  EnoughLegsOfLamb()
  AlertSheriff()
  CheckTuckCondition()
  HaslockMoneyTaken()
  UnlockDoor16()

  if (Globals.hasTalkedToHidingSon and not Globals.LadyIsHome) then -- when talked to son and not talked to lady second time
    AttachScrollToNPC(GetActor("WomanCivilianFriend_9"), GetScroll("Scroll_22")) 
  end

  -- lokaler Helper
  local function enum_name(enum_tbl, value)
    for k, v in pairs(enum_tbl) do
      if v == value then return k end
    end
    return tostring(value)
  end

  -- Logging
  print(
    ("Mission: %s, Allan: %s, Tuck: %s, No. of PCs: %s")
    :format(
      enum_name(MissionStates, Globals.MissionState),
      enum_name(AllanState,   Globals.AllanStatus),
      enum_name(TuckState,    Globals.TuckStatus),
      tostring(GetNumberOfPCs())
    )
  )
end

function CheckVictoryCondition(secondsPassed)
  
  local exitLocations = { 
    "Node_19", "Node_20",
  }
  
  if (Globals.MissionState == MissionStates.spiedMeeting) then
        -- DEBUG: wie viele aktive PCs sind safe?
    local active = 0
    local safeCount = 0

    for i = 0, (GetNumberOfPCs()-1) do
      local pc = GetPC(i)
      if IsNull(pc) == false then
        if IsActorDead(pc) == false then
          active = active + 1
          if IsPCSafe(pc, exitLocations) == true then
            safeCount = safeCount + 1
          end
        end
      end
    end

    print(string.format(
      "[WINCHECK] active_pcs=%d safe_pcs=%d (nodes=%s,%s) missionState=%d",
      active, safeCount, tostring(exitLocations[1]), tostring(exitLocations[2]), Globals.MissionState
    ))
    --------------------Ende Löschen

    for i = 0, GetNumberOfPCs() do
      if IsNull(GetPC(i)) == false then
        if IsActorDead(GetPC(i)) == false then
          if IsPCSafe(GetPC(i), exitLocations) == false then -- winning condition
            return 0
          end
        end
      end
    end
    CompleteObjective(9)
    ChooseVictoryDefeatText(1)
    return 1
  elseif Globals.SheriffHasBeenWarned then -- Sheriff has been warned - losing condition
    ChooseVictoryDefeatText(3)    
    return 2
  elseif Globals.LoseByTuckDown or Globals.NotEnoughLegsOfLamb then -- Tuck out of action or less than 6 LegsOfLambs available - losing condition
    ChooseVictoryDefeatText(2)
    return 2

  else
    if not HasAnyPCActionWhoIsInThisLevelOrCouldMaybeComeFromSherwood(PCAction.BodyCarryMerryMan) then -- nobody left for supplying LegsOfLambs - losing condition
      if Globals.MissionState < MissionStates.spokeWithSpy then
        ChooseVictoryDefeatText(1)
        return 2    
      end  
    end
  end
end

----------------------------------------------------------------------------------
--Mission Code 
----------------------------------------------------------------------------------

--Actors

FirstConversationWithAllan = {
  Taken = function(actorSource)
    AttachScrollToNPC(GetActor("Allan_1"), God())
    Globals.MissionState = MissionStates.hasTalkedToAllan
    Globals.AllanStatus = AllanState.HintToCathedral
    CompleteObjective(2)
    AddObjective(3, true)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(6)
    Then()
    SequenceFreezeAll(false)
    SequenceUnLockUser()
    EndSequence()
    return 1
  end,
}

ConversationWithAllanAfterTuck = {
  Taken = function(actorSource)
    AttachScrollToNPC(GetActor("Allan_1"), God())
    CompleteObjective(5)
    AddObjective(6, false)

    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(11)
    Then()
    SequenceTimer(15)
    Then()
    SequenceScrollCameraTo(GetActorLocation(GetItem("LegsOfLamb_11")))
    Then()
    SequenceTimer(15)
    Then()
    SequenceCall(function()
      ActivateItems({
        GetItem("LegsOfLamb_11"),
        GetItem("LegsOfLamb_20"),
        GetItem("LegsOfLamb_21"),
        GetItem("LegsOfLamb_24")
      })
    end)
    Then()
    SequenceTimer(25)
    Then()
    SequenceScrollCameraTo(GetActorLocation(GetItem("LegsOfLamb_18")))
    Then()
    SequenceTimer(15)
    Then()
    SequenceCall(function()
      ActivateItems({
        GetItem("LegsOfLamb_18"),
        GetItem("LegsOfLamb_22"),
        GetItem("LegsOfLamb_23")
      })
    end)
    Then()
    SequenceTimer(25)
    Then()
    SequenceJumpCameraTo(GetActorLocation(actorSource))
    SequenceFreezeAll(false)
    SequenceUnLockUser()
    EndSequence()
    Globals.AllanStatus = AllanState.LambInCastle -- activate "check sufficient lambs functions"
    return 1
  end,
}

FriarTuck_6_Talk = {
  Taken = function(actorSource)
    AttachScrollToNPC(GetActor("FriarTuck_6"), God())

    -- Nur aktiv, wenn Tuck bereits freigeschaltet ist
    if Globals.MissionState ~= MissionStates.spokeWithTuck then
      return 0
    end

    -- 1) Der falsche Charakter spricht Tuck an -> Text 21
    if not HasPCAction(actorSource, PCAction.MeatMerryMan) then
      StartSequence()
      SequenceDisplayPopupText(21)
      EndSequence()
      print("wrong PC talked to Tuck")
      return 1
    end

    -- 2) Prüfen, wie viele Lammkeulen der richtige Träger aktuell hat (PersistentProperty.lamb)
    local lambs = GetPersistentProperty(actorSource, PersistentProperty.lamb) or 0
    if lambs <= 0 then
      
      StartSequence()
      SequenceDisplayPopupText(27)
      EndSequence()
      print("No Legs of Lamb in inventory (persistent)")
      return 1
    end

    -- 3) Übergabe bis zum benötigten Maximum
    local needed      = Globals.RequiredLegsOfLamb - Globals.GivenLegsOfLamb
    local to_transfer = math.min(lambs, math.max(0, needed))

    if to_transfer > 0 then
      -- Persistente Anzahl beim PC reduzieren …
      SetPersistentProperty(actorSource, PersistentProperty.lamb, lambs - to_transfer)
      -- … und globale Fortschritte hochzählen
      Globals.GivenLegsOfLamb = Globals.GivenLegsOfLamb + to_transfer

      print(string.format("Handover Legs of Lamb: +%d (now %d/%d)", to_transfer, Globals.GivenLegsOfLamb, Globals.RequiredLegsOfLamb))


      -- Sufficient amount of lambs given to Tuck
      if Globals.GivenLegsOfLamb >= Globals.RequiredLegsOfLamb then
        Globals.TuckStatus = TuckState.EnoughLegsOfLambs
        AddObjective(7, true)
        CompleteObjective(4)
        CompleteObjective(6)
        
        StartSequence()
        SequenceDisplayPopupText(13) 
        EndSequence()
        return 1
      end


      -- Lambs given to Tuck, but not sufficient yet
      StartSequence()
      SequenceDisplayPopupText(12)
      EndSequence()
      return 1
    end

    -- Fallback (sollte praktisch nie erreicht werden)
    return 0
  end,
}

TuckActivatesSpy = {
  Taken = function(actorSource)
    local spy = GetActor("Spy_7")
    AttachScrollToNPC(GetActor("FriarTuck_6"), God())  
    
    if IsActorEqual(actorSource, GetRobin()) then
      CompleteObjective(7)
      AddObjective(8, true)  
      StartSequence()
      SequenceLockUser()
      Then()
      SequenceScrollCameraTo(GetActorLocation(actorSource))
      Then()
      SequenceTimer(15)
      SequenceDisplayPopupText(14)
      Then()
      SequenceCall(function() MovePersonInsideSacristy(GetActor("FriarTuck_6")) end)
      Then()
      SequenceTimer(60)
      Then()
      SequenceCall(function()
        Activate(spy)
        StopActor(spy)
        SetAIState(spy, AiState.script)
      end)
      Then()
      SequenceReveal(spy)
      Then()
      SequenceLockAI(spy)
      Then()
      SequenceMove(spy, GetLocation("Node_32"), MovementStyle.walking)
      Then()
      SequenceTurnTo(spy, GetActorLocation(GetRobin()))
      Then()
      SequenceDisplayPopupText(15)
      Then()
      SequenceTimer(15)
      Then()
      SequenceCall(function()
        ChevaliersTakeBreak() -- orange Chevaliers to be removed for making it possible ot overhear meeting
      end)
      Then()
      SequenceTimer(300)
      Then()
      SequenceScrollCameraTo(GetActorLocation(actorSource))
      Then()
      SequenceCall(function() MovePersonInsideSacristy(spy) end)
      Then()
      SequenceUnLockUser()
      EndSequence()
      Globals.MissionState = MissionStates.spokeWithSpy

    else
      StartSequence()
      SequenceLockUser()
      SequenceFreezeAll(true)
      Then()
      SequenceScrollCameraTo(GetActorLocation(actorSource))
      Then()
      SequenceTimer(15)
      SequenceDisplayPopupText(8)
      Then()
      SequenceFreezeAll(false)
      SequenceUnLockUser()
      EndSequence()
      Globals.TuckStatus = TuckState.EnoughLegsOfLambs -- Reactivate ScrollToNPC
    end
    return 1

  end,
}



-- Optional: Lady Looking for Her Son

LadyLooksForSon = {
  Taken = function(actorSource)
    AttachScrollToNPC(GetActor("WomanCivilianFriend_9"), God())
    StartSequence()
    AddObjective(14, false)
    SequenceLockUser()
    SequenceFreezeAll(true)
    Then()
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(24)
    Then()
    SequenceFreezeAll(false)
    SequenceUnLockUser()
    EndSequence()
    Globals.hasTalkedToSearchingLady = true
    return 1
  end,
}

HidingSonFound = {
  Taken = function(actorSource)
    AttachScrollToNPC(GetActor("Child_10"), God())
    StartSequence()
    CompleteObjective(14)
    SequenceLockUser()
    SequenceFreezeAll(true)
    Then()
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(25)
    Then()
    SequenceCall(function() MoveInsideHouseRunning(GetActor("Child_10")) end)
    Then()
    SequenceFreezeAll(false)
    SequenceUnLockUser()
    EndSequence()
    Globals.hasTalkedToHidingSon = true
    return 1
  end,
}

LadySonBackHome = {
  Taken = function(actorSource)
    AttachScrollToNPC(GetActor("WomanCivilianFriend_9"), God())
    StartSequence()
    AddObjective(14, false)
    SequenceLockUser()
    SequenceFreezeAll(true)
    Then()
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(26)
    Then()
    SequenceCall(function()
      ActivateItems({
        GetItem("Clovers_13"),
        GetItem("Money_5")
      })
    end)
    SequenceCall(function() MoveInsideHouseWalking(GetActor("WomanCivilianFriend_9")) end)
    Then()
    SequenceFreezeAll(false)
    SequenceUnLockUser()
    EndSequence()
    Globals.LadyIsHome = true
    return 1
  end,
}



-- === Legs of Lamb: Units + robust "still on ground" detection ===

-- Feste Einheiten pro Map-Item
local LAMB_ITEM_UNITS = {
  LegsOfLamb_11 = 1,
  LegsOfLamb_18 = 1,
  LegsOfLamb_20 = 1,
  LegsOfLamb_21 = 1,
  LegsOfLamb_22 = 1,
  LegsOfLamb_23 = 1,
  LegsOfLamb_24 = 1,
}

-- Ist das Item noch „auf dem Boden/in der Welt“ verfügbar?
local function _is_item_still_on_ground(it)
  if not it then return false end
  if IsNull and IsNull(it) then return false end

  -- wenn die Engine solche Flags kennt: raus, sobald unsichtbar/ausgeschaltet
  if IsDeactivated and IsDeactivated(it) then return false end
  if IsActive and (not IsActive(it)) then return false end
  if IsHidden and IsHidden(it) then return false end

  -- wenn das Item bereits einem Träger gehört / im Inventar ist
  if GetOwner and GetOwner(it) then return false end
  if IsInInventory and IsInInventory(it) then return false end
  if GetItemHolder and GetItemHolder(it) then return false end

  -- optional: wenn es keine Welt-Position hat (manche Engines)
  if GetItemLocation and (not GetItemLocation(it)) then return false end

  return true
end

-- Zählt die Stückzahl, die noch am Boden liegt (nicht aufgenommen)
local function _count_lamb_on_map()
  local u11 = 1   -- important: needs to be adapted if item quantity is changed in spellforge!
  local u18 = 1   -- important: needs to be adapted if item quantity is changed in spellforge!
  local u20 = 1
  local u21 = 1
  local u22 = 1
  local u23 = 1
  local u24 = 1

  local sum = u11 + u18 + u20 + u21 + u22 + u23 + u24

  local hasIBIP = (type(IsBonusItemPickedUp) == "function")
  local p11, p18, p20, p21, p22, p23, p24 = nil, nil, nil, nil, nil, nil, nil

  if hasIBIP then
    p11 = IsBonusItemPickedUp(GetItem("LegsOfLamb_11"))
    p18 = IsBonusItemPickedUp(GetItem("LegsOfLamb_18"))
    p20 = IsBonusItemPickedUp(GetItem("LegsOfLamb_20"))
    p21 = IsBonusItemPickedUp(GetItem("LegsOfLamb_21"))
    p22 = IsBonusItemPickedUp(GetItem("LegsOfLamb_22"))
    p23 = IsBonusItemPickedUp(GetItem("LegsOfLamb_23"))
    p24 = IsBonusItemPickedUp(GetItem("LegsOfLamb_24"))

    if p11 == true then sum = sum - u11 end
    if p18 == true then sum = sum - u18 end
    if p20 == true then sum = sum - u20 end
    if p21 == true then sum = sum - u21 end
    if p22 == true then sum = sum - u22 end
    if p23 == true then sum = sum - u23 end
    if p24 == true then sum = sum - u24 end
  else
    -- Fallback (nur falls IBIP nicht existiert): Item liegt nicht mehr am Boden → abziehen
    local it11 = GetItem and GetItem("LegsOfLamb_11")
    local it18 = GetItem and GetItem("LegsOfLamb_18")
    local it20 = GetItem and GetItem("LegsOfLamb_20")
    local it21 = GetItem and GetItem("LegsOfLamb_21")
    local it22 = GetItem and GetItem("LegsOfLamb_22")
    local it23 = GetItem and GetItem("LegsOfLamb_23")
    local it24 = GetItem and GetItem("LegsOfLamb_24")

    if not (it11 and _is_item_still_on_ground(it11)) then sum = sum - u11 end
    if not (it18 and _is_item_still_on_ground(it18)) then sum = sum - u18 end
    if not (it20 and _is_item_still_on_ground(it20)) then sum = sum - u20 end
    if not (it21 and _is_item_still_on_ground(it21)) then sum = sum - u21 end
    if not (it22 and _is_item_still_on_ground(it22)) then sum = sum - u22 end
    if not (it23 and _is_item_still_on_ground(it23)) then sum = sum - u23 end
    if not (it24 and _is_item_still_on_ground(it24)) then sum = sum - u24 end
  end

  if sum < 0 then sum = 0 end

  -- Debug: zeigt, ob IBIP existiert und was es für jedes Item liefert
  print(string.format(
    "[LambCheck] IBIP_exists=%s picked_11=%s picked_18=%s picked_20=%s picked_21=%s picked_22=%s picked_23=%s picked_24=%s -> on_map=%d",
    tostring(hasIBIP),
    tostring(p11), tostring(p18), tostring(p20), tostring(p21), tostring(p22), tostring(p23), tostring(p24),
    sum
  ))

  return sum
end

-- Du meintest: _count_lamb_on_pcs() funktioniert bei dir bereits.
-- Falls du ihn doch brauchst, hier noch einmal:
local function _count_lamb_on_pcs()
  local sum = 0
  if not GetNumberOfPCs or not GetPC then return 0 end
  for i = 0, GetNumberOfPCs() do
    local pc = GetPC(i)
    if pc and (not (IsNull and IsNull(pc))) and (not (IsActorDead and IsActorDead(pc))) then
      local carried = GetPersistentProperty and GetPersistentProperty(pc, PersistentProperty.lamb) or 0
      if carried and carried > 0 then
        sum = sum + carried
      end
    end
  end
  return sum
end

-- High-level Check (von Timer() aufgerufen)
function EnoughLegsOfLamb()
  if ((Globals.TuckStatus < TuckState.SpyActivated) and (Globals.AllanStatus == AllanState.LambInCastle)) then
    -- aktuelle Bestände
    local carried = _count_lamb_on_pcs()
    local on_map  = _count_lamb_on_map()
    local total   = carried + on_map

    -- Restbedarf = Required - Already Given (nicht negativ)
    local required = tonumber(Globals.RequiredLegsOfLamb)
    local given    = tonumber(Globals.GivenLegsOfLamb)
    local needed   = required - given
    if needed < 0 then needed = 0 end

    -- Flag setzen
    Globals.NotEnoughLegsOfLamb = (total < needed)

    -- Debug
    print(string.format(
      "[LambCheck] carried=%d on_map=%d total=%d required=%d given=%d needed=%d NotEnough=%s",
      carried, on_map, total, required, given, needed, tostring(Globals.NotEnoughLegsOfLamb)
    ))
  end
end



-- Castle Alerting Functions

-- Soldaten, die bei "alerted" als Melder laufen sollen
local ALERT_MESSENGERS = {
  "Hallebardier_Orange_1",
  "Hallebardier_Orange_2",
  "Hallebardier_Orange_3",
  "Hallebardier_Orange_4",
  "Arbaletrier_Orange_26",
  "Lancier_Orange_27",
  "Lancier_Orange_28",
  "Epee_Orange_29",
  "Epee_Orange_30",
  "Chevalier_Orange_82",
  "Chevalier_Orange_113",
  "Chevalier_Orange_114",
  "Chevalier_Orange_115",
  "Chevalier_Orange_116",
  "Chevalier_Orange_117",
  "Chevalier_Orange_118",
  "Chevalier_Orange_119"
}

-- Zustände pro Melder: nil | "dispatched" | "done"
local MessengerState = {}

-- Flag, damit die Folge-Sequenz außerhalb der Move-Sequence sauber gestartet wird
Globals.PendingSheriffWarning = Globals.PendingSheriffWarning or false

-- Distanz-Helper (nutzt vorhandene Enginefunktionen, fällt sonst zurück)
local function _dist_between(pos, loc)
  if GetDistance then
    return GetDistance(pos, loc)
  elseif Distance then
    return Distance(pos, loc)
  elseif GetDistanceBetweenLocations then
    return GetDistanceBetweenLocations(pos, loc)
  elseif GetDistance2D then
    return GetDistance2D(pos, loc)
  end
  return nil
end

-- Liefert "Node_4" oder "Node_7" – Name, nicht das Location-Objekt
local function _nearest_target_name_for(actor)
  local pos = GetActorLocation(actor)
  local loc4 = GetLocation("Node_4")
  local loc7 = GetLocation("Node_7")

  local d4 = _dist_between(pos, loc4)
  local d7 = _dist_between(pos, loc7)

  if d4 and d7 then
    return (d7 < d4) and "Node_7" or "Node_4"
  end
  -- Kein Distanz-API verfügbar → konservativer Default
  return "Node_4"
end

-- Was nach Ankunft passieren soll
local function OnMessengerArrived(messengerName)
  local a = GetActor(messengerName)
  if not a then return end

  StartSequence()
  SequencePlayAnim(a, 206)  -- Melde-Animation
  Then()
  SequenceTimer(10)
  Then()
  SequenceSpeak(a, 51, 0)   -- sagt Zeile 51 (Variante 0)
  Then()
  SequenceCall(function()
    if not Globals.SheriffHasBeenWarned then
      SheriffHasBeenWarned()
      UnlockAI(a)
      SetAIState(a, AiState.wondering)
    end
  end)
  
  EndSequence()
end

-- Prüft zyklisch, ob einer der Melder "alerted" ist, schickt ihn los, markiert Ankunft
function AlertSheriff()
  if Globals.SheriffHasBeenWarned == false then
    for _, name in ipairs(ALERT_MESSENGERS) do
      if MessengerState[name] ~= "dispatched" and MessengerState[name] ~= "done" then
        local a = GetActor(name)
        if a then
          local st = GetAIState(a)
          --if st == AiState.seeking or st == AiState.menacing or st == AiState.attacking then
          if st == AiState.menacing or st == AiState.attacking then
            MessengerState[name] = "dispatched"

            StartSequence()
            SequenceCall(function()
              StopActor(a)
              SetAIState(a, AiState.script)
            end)
            Then()
            SequenceLockAI(a)
            Then()
            -- WICHTIG: Zielname wählen und Location JETZT holen (wie im Original, das funktionierte)
            local targetName = _nearest_target_name_for(a)
            SequenceMove(a, GetLocation(targetName), MovementStyle.running)
            Then()
            SequenceCall(function()
              LockOnPlace(a)
              OnMessengerArrived(name)
              MessengerState[name] = "done"
            end)
            EndSequence()
          end
        end
      end
    end
  end
end

function CheckTuckCondition()
  local tuck = GetActor("FriarTuck_6")
  if not tuck then return end
  if IsActorDead(tuck) or IsActorOutOfAction(tuck) then
    Globals.LoseByTuckDown = true
    -- ForceCheckVictory()   -- immediate check
  end
end


OffBEP01_8000036c = {
  ActionChange = function(action, oldAction)
    if not Globals.OfficerCalledSoldiers then
      if GetAIState(GetActor("Officier_Rouge_92")) <= AiState.wondering then
        Globals.OfficerCalledSoldiers = true
        AddAsSquadMember(GetActor("Officier_Rouge_92"), GetActor("Epee_Rouge_93"))
        AddAsSquadMember(GetActor("Officier_Rouge_92"), GetActor("Epee_Rouge_94"))
      end
    end
  end,

  FilterAiEvent = function(actorSource, event)
    return 1
  end
}

--Targets
mecanisme_80000030 = {
  ActivatedBySword = function(actorSource)
    if not IsPatchApplied(GetPatchScript(CastleFallGateRoom.fallGate)) then
      CastleFallGateRoom:ActivateFallGate(GetLocation("Node_8"))
    end
  end,
}

--Scrolls

ScrollAllanHouseUnknown = {
  Taken = function(actorSource)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(20)
    Then()
    SequenceDisplayPopupText(2)
    Then()
    SequenceUnLockUser()
    SequenceFreezeAll(false)
    EndSequence()
    return 1
  end,
}

ScrollAllanHouse = {
  Taken = function(actorSource)
    CompleteObjective(1)
    AddObjective(2, true)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(4)
    Then()
    SequenceTimer(15)
    Then()
    SequenceScrollCameraTo(GetLocation("Node_24"))
    Then()
    SequenceTimer(15)
    Then()
    SequenceSetZoomLevel(2)
    Then()
    SequenceTimer(25)
    Then()

    -- Helper: reveal nur, wenn Actor aktiv ist
    local function reveal_if_active(actor_name)
      local a = GetActor(actor_name)
      if a and not IsActorOutOfAction(a) then
        SequenceScrollCameraTo(GetActorLocation(a))
        Then()
        SequenceTimer(15)
        Then()
        SequenceReveal(a)
        Then()
        SequenceTimer(25)
      end
    end

    -- Cavalier 107 (nur wenn nicht out of action)
    reveal_if_active("Cavalier_Jaune_107")

    -- Cavalier 108 (nur wenn nicht out of action)
    reveal_if_active("Cavalier_Jaune_108")

    SequenceSetZoomLevel(1)
    Then()
    SequenceTimer(15)
    Then()
    SequenceJumpCameraTo(GetActorLocation(actorSource)) 
    Then()
    SequenceUnLockUser()
    SequenceFreezeAll(false)
    EndSequence()
    Globals.AllanStatus = AllanState.HouseIsKnown
    return 1
  end,
}


ScrollWarningCastleSoldiers = {
  Taken = function(actorSource)
    AddObjective(12, false)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(5)
    Then()
    SequenceSetZoomLevel(1)
    Then()
    SequenceScrollCameraTo(GetLocation("Node_26"))
    Then()
    SequenceTimer(25)
    Then()
    SequenceJumpCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceUnLockUser()
    SequenceFreezeAll(false)
    EndSequence()
    return 1
  end,
}

ScrollNextMendicantRecommended = {
  Taken = function(actorSource)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(3)
    Then()
    SequenceScrollCameraTo(GetActorLocation(GetActor("Mendicant_13")))
    Then()
    SequenceTimer(15)
    Then()
    SequenceReveal(GetActor("Mendicant_13"))
    Then()
    SequenceTimer(25)
    Then()
    SequenceScrollCameraTo(GetActorLocation(GetActor("Mendicant_11")))
    Then()
    SequenceTimer(15)
    Then()
    SequenceReveal(GetActor("Mendicant_11"))
    Then()
    SequenceTimer(25)
    Then()
    SequenceJumpCameraTo(GetActorLocation(actorSource))
    SequenceUnLockUser()
    SequenceFreezeAll(false)
    EndSequence()
    return 1
  end,
}

ScrollRevealCathedralSoldiers = {
  Taken = function(actorSource)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceSetZoomLevel(1)
    Then()
    SequenceScrollCameraTo(GetLocation("Node_23"))
    Then()
    SequenceTimer(15)
    Then()
    SequenceReveal(GetActor("Hallebardier_Jaune_54"))
    SequenceReveal(GetActor("Hallebardier_Jaune_55"))
    SequenceReveal(GetActor("Hallebardier_Jaune_105"))
    SequenceReveal(GetActor("Chevalier_Jaune_58"))
    SequenceReveal(GetActor("Archer_Jaune_9"))
    SequenceReveal(GetActor("Archer_Jaune_10"))
    SequenceReveal(GetActor("Officier_Orange_35"))
    SequenceReveal(GetActor("Chevalier_Jaune_106"))
    SequenceReveal(GetActor("Hallebardier_Jaune_59"))
    SequenceReveal(GetActor("Epee_Jaune_53"))
    SequenceReveal(GetActor("Arbaletrier_Jaune_52"))
    Then()
    SequenceTimer(40)
    Then()
    SequenceJumpCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceUnLockUser()
    SequenceFreezeAll(false)
    EndSequence()
    return 1
  end,
}

ScrollRevealCastleSoldiers = {
  Taken = function(actorSource)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceSetZoomLevel(1)
    Then()
    SequenceScrollCameraTo(GetLocation("Node_26"))
    Then()
    SequenceTimer(15)
    Then()
    SequenceReveal(GetActor("Hallebardier_Orange_1"))
    SequenceReveal(GetActor("Chevalier_Orange_82"))
    SequenceReveal(GetActor("Hallebardier_Orange_3"))
    SequenceReveal(GetActor("Arbaletrier_Orange_26"))
    SequenceReveal(GetActor("Lancier_Orange_27"))
    SequenceReveal(GetActor("Epee_Orange_29"))
    SequenceReveal(GetActor("Lancier_Orange_28"))
    SequenceReveal(GetActor("Epee_Orange_30"))
    SequenceReveal(GetActor("Hallebardier_Orange_4"))
    SequenceReveal(GetActor("Hallebardier_Orange_2"))
    SequenceReveal(GetActor("Chevalier_Orange_113"))
    SequenceReveal(GetActor("Chevalier_Orange_114"))
    SequenceReveal(GetActor("Chevalier_Orange_115"))
    SequenceReveal(GetActor("Chevalier_Orange_116"))
    SequenceReveal(GetActor("Chevalier_Orange_117"))
    SequenceReveal(GetActor("Chevalier_Orange_118"))
    SequenceReveal(GetActor("Chevalier_Orange_119"))
    Then()
    SequenceTimer(40)
    Then()
    SequenceJumpCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceUnLockUser()
    SequenceFreezeAll(false)
    EndSequence()
    return 1
  end,
}

ScrollActivateMarketItems = {
  Taken = function(actorSource)
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(15)
    Then()
    SequenceDisplayPopupText(28)
    Then()
    SequenceTimer(15)
    Then()
    SequenceCall(function()
      ActivateMarketItems()
    end)
    Then()
    SequenceTimer(15)
    Then()
    SequenceUnLockUser()
    SequenceFreezeAll(false)
    EndSequence()
    return 1
  end,
}

ScrollActivateHaslock = {
  Taken = function(actorSource)
    Activate(GetActor("Haslock_8"))
    StartSequence()
    SequenceLockUser()
    SequenceFreezeAll(true)
    SequenceScrollCameraTo(GetActorLocation(actorSource))
    Then()
    SequenceTimer(20)
    Then()
    SequenceDisplayPopupText(23)
    Then()
    SequenceTimer(15)
    Then()
    SequenceReveal(GetActor("Haslock_8"))
    Then()
    LockAI(GetActor("Haslock_8"), false)
    Then()
    SequenceScrollCameraTo(GetLocation("Node_41"))
    Then()
    SequenceFreezeAll(false)
    Then()
    SequenceMove(GetActor("Haslock_8"), GetLocation("Node_41"), MovementStyle.walking)
    Then()
    SequenceTurnTo(GetActor("Haslock_8"), GetLocation("Node_40"))
    Then()
    SequenceTimer(15)
    Then()
    SequenceJumpCameraTo(GetActorLocation(actorSource))
    AssignPatrol(GetActor("Haslock_8"), GetPatrol("Patrol_88"))
    SequenceUnLockUser()
    EndSequence()
    return 1
  end,
} 

-- Testing Scrolls - not relevant for playing - can be deleted

ScrollTestSheriffWarning = {
  Taken = function(actorSource)
    SheriffHasBeenWarned()
  end,
}

ScrollTestMoveChevaliersInside = {
  Taken = function(actorSource)
    ChevaliersTakeBreak()
  end,
}


ScrollTestWinning = {
  Taken = function(actorSource)
    Globals.MissionState = MissionStates.spiedMeeting
  end,

}
-- end of lines that could be deleted


-- Supporting Functions For Actors

function RobinSpiesSheriffMeetingArea1(actor)
  -- Sicherheitsnetz: nur Robin darf auslösen
  if not IsActorEqual(actor, GetRobin()) then
    StopActor(actor)
    StartSequence()
    SequenceLockUser()
    Then()
    SequenceDisplayPopupText(29)
    Then()
    SequenceMove(actor, GetLocation("Node_34"), MovementStyle.walking)
    Then()
    SequenceUnLockUser()
    EndSequence()
    return
  end

  StartSequence()
  SequenceLockUser()
  Then()
  SequenceCall(LockAllAI)
  Then()
  SequenceScrollCameraTo(GetActorLocation(GetActor("Sheriff_3")))
  Then()
  SequenceReveal(GetActor("Scathlock_2"))
  Then()
  SequenceReveal(GetActor("Sheriff_3"))
  Then()
  SequenceReveal(GetActor("Longchamp_5"))
  Then()
  SequenceReveal(GetActor("Chevalier_Noir_24"))
  Then()
  SequenceReveal(GetActor("Chevalier_Noir_25"))
  Then()
  SequenceTimer(15)
  SequenceCall(function()
      SetNPCEmoticon(GetActor("Sheriff_3"), 5, 30)
    end)
  Then()
  SequenceMove(GetActor("Sheriff_3"), GetLocation("Node_37"), MovementStyle.showingRightArm)
  Then()
  SequenceTurnTo(GetActor("Sheriff_3"),GetActorLocation(GetActor("Chevalier_Noir_25")))
  Then()
  SequenceTimer(15)
  Then()
  SequencePlayAnim(GetActor("Sheriff_3"), AnimationAction.provoking)
  Then()
  SequenceTimer(15)
  Then()
  SequencePlayDialog(2)
  -- SequenceDisplayPopupText(17) -- old popup texts, replaced by dialogue
  -- Then()
  -- SequenceTimer(15)
  -- Then()
  -- SequenceDisplayPopupText(18)
  -- Then()
  -- SequenceTimer(15)
  -- Then()
  -- SequenceDisplayPopupText(19)
  -- Then()
  SequenceTimer(15)
  Then()
  SequenceMove(actor, GetLocation("Node_34"), MovementStyle.walking)
  Then()
  SequenceDisplayPopupText(20)
  Then()
  SequenceCall(function()
    Globals.MissionState = MissionStates.spiedMeeting
  end)
  Then()
  SequenceCall(UnlockUnlockableAI)
  SequenceUnLockUser()
  EndSequence()
  CompleteObjective(0)
  CompleteObjective(8)
  AddObjective(9, true)
  ActivateSherwoodSigns()
end

function RobinSpiesSheriffMeetingArea2(actor)
  -- Sicherheitsnetz: nur Robin darf auslösen
  if not IsActorEqual(actor, GetRobin()) then
    StopActor(actor)
    StartSequence()
    SequenceLockUser()
    Then()
    SequenceDisplayPopupText(29)
    Then()
    SequenceMove(actor, GetLocation("Node_42"), MovementStyle.walking)
    Then()
    SequenceUnLockUser()
    EndSequence()
    return
  end

  StartSequence()
  SequenceLockUser()
  Then()
  SequenceCall(LockAllAI)
  Then()
  SequenceScrollCameraTo(GetActorLocation(GetActor("Sheriff_3")))
  Then()
  SequenceReveal(GetActor("Scathlock_2"))
  Then()
  SequenceReveal(GetActor("Sheriff_3"))
  Then()
  SequenceReveal(GetActor("Longchamp_5"))
  Then()
  SequenceReveal(GetActor("Chevalier_Noir_24"))
  Then()
  SequenceReveal(GetActor("Chevalier_Noir_25"))
  Then()
  SequenceTimer(15)
  SequenceCall(function()
      SetNPCEmoticon(GetActor("Sheriff_3"), 5, 30)
    end)
  Then()
  SequenceMove(GetActor("Sheriff_3"), GetLocation("Node_37"),MovementStyle.walking)
  Then()
  SequenceTurnTo(GetActor("Sheriff_3"),GetActorLocation(GetActor("Chevalier_Noir_25")))
  Then()
  SequenceTimer(15)
  Then()
  SequencePlayAnim(GetActor("Sheriff_3"), 206)
  Then()
  SequenceTimer(15)
  Then()
  SequencePlayDialog(2)
  -- SequenceDisplayPopupText(17) -- old popup texts, replaced by dialogue
  -- Then()
  -- SequenceTimer(15)
  -- Then()
  -- SequenceDisplayPopupText(18)
  -- Then()
  -- SequenceTimer(15)
  -- Then()
  -- SequenceDisplayPopupText(19)
  -- Then()
  SequenceTimer(15)
  Then()
  SequenceMove(actor, GetLocation("Node_42"), MovementStyle.walking)
  Then()
  SequenceDisplayPopupText(20)
  Then()
  SequenceCall(function()
    Globals.MissionState = MissionStates.spiedMeeting
    
  end)
  Then()
  SequenceCall(UnlockUnlockableAI)
  SequenceUnLockUser()
  EndSequence()
  CompleteObjective(0)
  CompleteObjective(8)
  AddObjective(9, true)
  ActivateSherwoodSigns()
end

function SheriffHasBeenWarned()
  RevealCastleHall()
  LockOnPlace(GetActor("Chevalier_Noir_24"))
  LockOnPlace(GetActor("Chevalier_Noir_25"))
  StartSequence()
  SequenceLockUser()
  -- SequenceCall(LockAllAI)
  Then()
  SequenceScrollCameraTo(GetActorLocation(GetActor("Sheriff_3")))
  Then()
  SequenceTimer(15)
  Then()
  SequenceSetZoomLevel(ZoomLevel.default)
  Then()
  SequenceReveal(GetActor("Scathlock_2"))
  Then()
  SequenceReveal(GetActor("Sheriff_3"))
  Then()
  SequenceReveal(GetActor("Longchamp_5"))
  Then()
  SequenceReveal(GetActor("Chevalier_Noir_24"))
  Then()
  SequenceReveal(GetActor("Chevalier_Noir_25"))
  Then()
  SequenceTimer(5)
  SequenceCall(function()
      SetNPCEmoticon(GetActor("Sheriff_3"), 6, 30)
    end)
  Then()
  SequenceTimer(5)
  Then()
  SequenceSpeak(GetActor("Sheriff_3"), 114, 2)
  Then()
  SequenceTimer(30)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Scathlock_2"), 2, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Noir_24"), 2, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Noir_25"), 2, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Scathlock_2"), 2, 30)
  end)
  Then()
  SequenceSpeak(GetActor("Scathlock_2"), 106, 0)

  SequenceCall(function() MovePersonsInside(GetActor("Scathlock_2")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MovePersonsInside(GetActor("Sheriff_3")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MovePersonsInside(GetActor("Longchamp_5")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MovePersonsInside(GetActor("Chevalier_Noir_24")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MovePersonsInside(GetActor("Chevalier_Noir_25")) end)
  SequenceTimer(40)
  Then()
  SequenceCall(function ()
    Globals.SheriffHasBeenWarned = true
  end)
  SequenceUnLockUser()
  EndSequence()

end

function MovePersonsInside(soldier)
  StartSequence()
  SequenceLockAI(soldier)
  Then()
  SequenceMoveIntoBuilding(soldier, GetLocation("Node_1"), MovementStyle.running)
  
  EndSequence()
end

function ChevaliersTakeBreak()
  RevealCastleHallway()
  StartSequence()
  SequenceLockUser()
  SequenceScrollCameraTo(GetLocation("Node_35"))
  Then()
  SequenceTimer(15)
  Then()
  SequenceSetZoomLevel(ZoomLevel.default)
  Then()
  SequenceTimer(15)
  Then()
  SequenceReveal(GetActor("Chevalier_Orange_114"))
  Then()
  SequenceReveal(GetActor("Chevalier_Orange_115"))
  Then()
  SequenceReveal(GetActor("Chevalier_Orange_116"))
  Then()
  SequenceReveal(GetActor("Chevalier_Orange_117"))
  Then()
  SequenceReveal(GetActor("Chevalier_Orange_118"))
  Then()
  SequenceReveal(GetActor("Chevalier_Orange_119"))
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Orange_114"), 5, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Orange_115"), 5, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Orange_116"), 5, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Orange_117"), 5, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Orange_118"), 5, 30)
  end)
  Then()
  SequenceCall(function()
    SetNPCEmoticon(GetActor("Chevalier_Orange_119"), 5, 30)
  end)
  Then()
  SequenceCall(function() MoveChevaliersInside(GetActor("Chevalier_Orange_114")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MoveChevaliersInside(GetActor("Chevalier_Orange_115")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MoveChevaliersInside(GetActor("Chevalier_Orange_116")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MoveChevaliersInside(GetActor("Chevalier_Orange_117")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MoveChevaliersInside(GetActor("Chevalier_Orange_118")) end)
  SequenceTimer(12)
  Then()
  SequenceCall(function() MoveChevaliersInside(GetActor("Chevalier_Orange_119")) end)
  SequenceTimer(40)
  Then() 
  SequenceUnLockUser()
  EndSequence()
end


function MoveChevaliersInside(soldier)
  StartSequence()
  SequenceLockAI(soldier)
  Then()
  SequenceMoveIntoBuilding(soldier, GetLocation("Node_35"), MovementStyle.walking)
  Then()
  SequenceCall(function() DeactivateInside(soldier) end)
  EndSequence()
end

function MovePersonInsideSacristy(actor)
  StartSequence()
  SequenceLockAI(actor)
  Then()
  SequenceMoveIntoBuilding(actor, GetLocation("Node_36"), MovementStyle.walking)
  Then()
  SequenceCall(function() DeactivateInside(actor) end)
  EndSequence()
end

function MoveInsideHouseRunning(actor)
  StartSequence()
  SequenceLockAI(actor)
  Then()
  SequenceMoveIntoBuilding(actor, GetLocation("Node_39"), MovementStyle.running)
  Then()
  SequenceCall(function() DeactivateInside(actor) end)
  EndSequence()
end

function MoveInsideHouseWalking(actor)
  StartSequence()
  SequenceLockAI(actor)
  Then()
  SequenceMoveIntoBuilding(actor, GetLocation("Node_39"), MovementStyle.walking)
  Then()
  SequenceCall(function() DeactivateInside(actor) end)
  EndSequence()
end

function ActivateAllan()
  if (Globals.AllanStatus == AllanState.HouseIsKnown) then
    Activate(GetActor("Allan_1"))
    Globals.AllanStatus = AllanState.ReadyToTalk

  elseif ((Globals.AllanStatus == AllanState.ReadyToTalk) and Globals.AllanLeavesHouse) then
    StartSequence()
    LockAI(GetActor("Allan_1"), false)
    Then()
    SequenceMove(GetActor("Allan_1"), GetLocation("Node_28"), MovementStyle.walking)
    Then()
    SequenceTurnTo(GetActor("Allan_1"), GetLocation("Node_24"))
    Then()
    EndSequence()
    AssignPatrol(GetActor("Allan_1"), GetPatrol("Patrol_82"))
    

  elseif (Globals.AllanStatus == AllanState.spokeWithTuck) then
    AssignPatrol(GetActor("Allan_1"), GetPatrol("Patrol_85")) -- Allan moves to market
    AttachScrollToNPC(GetActor("Allan_1"), GetScroll("Scroll_18"))
    Globals.AllanStatus = AllanState.ReadyToTalkAfterTuck -- avoid to attach scroll multiple times
  end
end

function ActivateTuck()
  if ((Globals.MissionState == MissionStates.spokeWithTuck) and (Globals.TuckStatus <= TuckState.ReadyToTalk)) then
    AttachScrollToNPC(GetActor("FriarTuck_6"), GetScroll("Scroll_24"))
    Globals.TuckStatus = TuckState.ReadyToTalk

  elseif ((Globals.MissionState == MissionStates.spokeWithTuck) and (Globals.TuckStatus == TuckState.EnoughLegsOfLambs)) then
    AttachScrollToNPC(GetActor("FriarTuck_6"), GetScroll("Scroll_20"))
    Globals.TuckStatus = TuckState.SpyActivated
  end

end

function ActivateMarketItems()
  return{
    Activate(GetItem("Apples_10")),
    Activate(GetItem("Stones_17")),
    Activate(GetItem("Nets_7")),
    Activate(GetItem("MedicinalHerbs_19"))
  }
end

function UnlockDoor16()
  if Globals.MissionState >= MissionStates.spokeWithTuck then
    SetDoorLockedPC(GetDoorScript(16), false)
  end
end

-- Optional: Rob Haslock
function HaslockMoneyTaken()
  if (GetPersistentProperty(GetActor("Haslock_8"), PersistentProperty.money) == 0) then
    CompleteObjective(13)
  end
end

--Zones

chateau_entree_80000032 = {
  Enter = function(actor)
    if IsActorPC(actor) then
      if not IsPatchApplied(GetPatchScript(CastleFallGateRoom.patch)) then
        CastleFallGateRoom:Reveal()
        StartSequence()
        SequencePlayAnimFreeze(GetActor("CastleTreadWheel"), AnimationAction.standingBored)
        EndSequence()
      end
    end
  end,
}

chateau_piece_discussion_80000033 = {
  Enter = function(actor)
    if not IsActorPC(actor) then return end

    if Globals.MissionState >= MissionStates.spokeWithSpy then
      RevealCastleHall()

      -- Nach der Spionage-Sequenz: alle werden geblockt -> Msg 29
      if Globals.MissionState >= MissionStates.spiedMeeting then
        StopActor(actor)
        StartSequence()
        SequenceSetZoomLevel(ZoomLevel.default)
        Then()
        SequenceLockUser()
        Then()
        SequenceDisplayPopupText(29)
        Then()
        SequenceMove(actor, GetLocation("Node_34"), MovementStyle.walking)
        Then()
        SequenceUnLockUser()
        EndSequence()
        return
      end

      -- Genau im Zustand 'spokeWithSpy': nur Robin darf die Sequenz starten
      if IsActorEqual(actor, GetRobin()) then
        StopActor(actor)
        RobinSpiesSheriffMeetingArea1(actor)
        return
      end

      -- Nicht-Robin vor dem ersten Durchlauf -> Msg 16
      StopActor(actor)
      StartSequence()
      SequenceSetZoomLevel(ZoomLevel.default)
      Then()
      SequenceLockUser()
      Then()
      SequenceDisplayPopupText(16)  -- <— hier geändert
      Then()
      SequenceMove(actor, GetLocation("Node_34"), MovementStyle.walking)
      Then()
      SequenceUnLockUser()
      EndSequence()
      return
    end
  end,
}

chateau_piece_discussion2_80000034 = {
  Enter = function(actor)
    if not IsActorPC(actor) then return end

    if Globals.MissionState >= MissionStates.spokeWithSpy then
      RevealCastleHall()

      -- Nach der Spionage-Sequenz: alle werden geblockt -> Msg 29
      if Globals.MissionState >= MissionStates.spiedMeeting then
        StopActor(actor)
        StartSequence()
        SequenceSetZoomLevel(ZoomLevel.default)
        Then()
        SequenceLockUser()
        Then()
        SequenceDisplayPopupText(29)
        Then()
        SequenceMove(actor, GetLocation("Node_42"), MovementStyle.walking)
        Then()
        SequenceUnLockUser()
        EndSequence()
        return
      end

      -- Genau im Zustand 'spokeWithSpy': nur Robin darf die Sequenz starten
      if IsActorEqual(actor, GetRobin()) then
        StopActor(actor)
        RobinSpiesSheriffMeetingArea2(actor)
        return
      end

      -- Nicht-Robin vor dem ersten Durchlauf -> Msg 16
      StopActor(actor)
      StartSequence()
      SequenceSetZoomLevel(ZoomLevel.default)
      Then()
      SequenceLockUser()
      Then()
      SequenceDisplayPopupText(16)  -- <— hier geändert
      Then()
      SequenceMove(actor, GetLocation("Node_42"), MovementStyle.walking)
      Then()
      SequenceUnLockUser()
      EndSequence()
      return
    end
  end,
}

chateau_piece02_80000039 = {
  Enter = function(actor)
    if (IsActorPC(actor) and Globals.MissionState >= MissionStates.spokeWithTuck)  then
      RevealCastleHallway()
    end
  end,
}

allan_house_area = {
  Enter = function(actor)
    if (IsActorEqual(actor, GetRobin())) then
      Globals.AllanLeavesHouse = true
    end
  end,
}

tuck_conversation_zone = {
  Enter = function(actor)
    if (Globals.MissionState < MissionStates.spokeWithTuck) then
      if IsActorEqual(GetRobin(), actor) then
        CompleteObjective(3)
        AddObjective(4, true)
        AddObjective(5, false)
        StartSequence()
        SequenceLockUser()
        SequenceFreezeAll(true)
        SequenceScrollCameraTo(GetActorLocation(actor))
        Then()
        -- alle laufenden Pfade sofort abbrechen
        SequenceCall(function ()
          StopActor(GetActor("FriarTuck_6"))
          SetAIState(GetActor("FriarTuck_6"), AiState.script)
          StopActor(GetRobin())
        end)
        Then()
        -- jetzt wieder bewegen lassen für die Choreografie
        SequenceFreezeAll(false)
        Then()
        -- choreografierte Positionierung
        SequenceMove(GetActor("FriarTuck_6"), GetLocation("Node_32"), MovementStyle.walking)
        Then()
        SequenceTurnTo(GetActor("FriarTuck_6"), GetLocation("Node_33"))
        Then()
        SequenceMove(GetRobin(), GetLocation("Node_33"), MovementStyle.running)
        Then()
        SequenceTurnTo(GetRobin(), GetLocation("Node_32"))
        Then()
        SequenceTimer(15)
        Then()
        --SequenceDisplayPopupText(9) -- old text message, replaced by dialogue
        SequencePlayDialog(0)
        Then()
        SequenceCall(function()
          StopActor(GetRobin())        
          LockOnPlace(GetRobin())
          Globals.MissionState = MissionStates.spokeWithTuck
          Globals.AllanStatus  = AllanState.spokeWithTuck      
        end)
        Then()
        SequenceLockAI(GetActor("FriarTuck_6"))
        Then()
        SequenceUnLockUser()
        Then()
        SequenceTimer(35)
        Then()
        SequencePlayDialog(1)
        Then()
        SequenceDisplayPopupText(10)
        Then()
        EndSequence()
      end
    end
  end,
}

eglise_entree_8000004b = {
  Enter = function(actor)
    if Globals.MissionState <= MissionStates.spokeWithTuck then
      if IsActorPC(actor) then
        local restrictAccess = true
        local text = 0
        if (Globals.MissionState == MissionStates.hasTalkedToAllan) then
          RevealCathedral()
          if (Globals.TuckTriggered == false) then
            text = 7
            Reveal(GetActor("FriarTuck_6"))
            Globals.TuckTriggered = true
          elseif IsActorEqual(GetRobin(), actor) then
            restrictAccess = false
            
          else
            text = 8
          end

        elseif (Globals.MissionState >= MissionStates.spokeWithTuck) then
          restrictAccess = false

        else
          text = 22
        end

        if restrictAccess then
          StopActor(actor)
          local remark = 14
          -- if IsActorEqual(actor, GetRobin()) then
          --   remark = 14
          -- end

          StartSequence()
          SequenceSetZoomLevel(ZoomLevel.default)
          Then()
          SequenceCall(LockAllAI)
          SequenceLockUser()
          Then()
          SequenceDisplayPopupText(text)
          Then()
          SequenceSpeakPC(actor, remark, 0)
          Then()
          SequenceMove(actor, GetLocation("Node_29"), MovementStyle.walking)
          Then()
          SequenceCall(UnlockUnlockableAI)
          SequenceUnLockUser()
          EndSequence()
        end     
      end
    end
  end,
}

child_hiding_area = {
  Enter = function(actor)
    if (IsActorPC(actor) and Globals.hasTalkedToSearchingLady and not Globals.hasTalkedToHidingSon) then
      AttachScrollToNPC(GetActor("Child_10"), GetScroll("Scroll_9"))
    end
  end,
}

EndZoneEst_80000224 = {
  Enter = function(actor)
    -- if IsActorPC(actor) then
    --   if Globals.MissionState == MissionStates.spiedMeeting then
    --       Globals.MissionState = MissionStates.Won
    --       ForceCheckVictory()          
    --   end
    -- end
  end,
}

EndZoneSud_80000225 = EndZoneEst_80000224

function RevealCastleHall()
  if not IsPatchApplied(GetPatchScript(CastleMainHall.patch)) then
    CastleMainHall:Reveal()
    RevealCastleHallway()
    SetDoorUnlockable(GetDoorScript(CastleMainHall.Door.entranceWest), false)
    SetDoorLockedPC(GetDoorScript(CastleMainHall.Door.entranceWest), false)

    SetDoorUnlockable(GetDoorScript(CastleMainHall.Door.entranceSouth), false)
    SetDoorLockedPC(GetDoorScript(CastleMainHall.Door.entranceSouth), false)

    DoorLockedButUnlockable(CastleMainHall.Door.tower)

  end
end

function RevealCastleHallway()
  if not IsPatchApplied(GetPatchScript(CastleHallway.patch)) then
    CastleHallway:Reveal()

  end
end

function RevealCathedral()
  if not IsPatchApplied(GetPatchScript(Church.patch)) then
    Church:Reveal()

  end
end