--[ ======================================== Stranger AI ======================================== ]
--The Stranger, a relentless creature that follows Mary wherever she goes.

--[ ====================================== Hostility Checker ==================================== ]
--AI is checking whether it is hostile to the player.
fnStranger_HostilityCheck = function(i)
    gzTextVar.bLastHostilityCheck = true
end

--[ ===================================== Post-Turn Spotter ===================================== ]
--This logic runs after turn execution. The entity cannot move but can attempt to spot the player
-- after movement has occurred. This prevents a quick door close from spotting the player.
--There is a percentage chance this may do nothing, depending on the AI.
fnStranger_PostTurnSpotCheck = function(i)
    
    --If the player is not a human, don't bother.
    if(gzTextVar.gzPlayer.sFormState ~= "Human") then return end

    --Common: Determine if we can see the player where we are.
    local bCanSeePlayer = fnStandardAI_SpotPlayer(i)

    --Entity is moving to the location where it last saw the player.
    if(gzTextVar.zEntities[i].sLastSawPlayer ~= "Nowhere") then
        
        --Can we see the player? Update chasing to the new destination.
        if(bCanSeePlayer == true) then
            gzTextVar.zEntities[i].sLastSawPlayer = gzTextVar.gzPlayer.sLocation
        end

    --We are not chasing the player, but we are patrolling back to where we started.
    elseif(gzTextVar.zEntities[i].sFirstSawPlayer ~= "Nowhere") then
        
        --If we spotted the player, resume the chase.
        if(bCanSeePlayer == true) then
        
            --Store the location where we spotted the player.
            gzTextVar.zEntities[i].sLastSawPlayer = gzTextVar.gzPlayer.sLocation
            
        --Can't see the player. Resume moving back to the starting location.
        else
        end
            
        --We handled the movement.
        return
        
    --Entity is neither chasing nor returning to the start of a chase.
    else
        
        --If we can see the player, initialize the chase.
        if(bCanSeePlayer == true) then
            
            --Store both the player's location and where we started the chase. Entity paths back to where they started.
            gzTextVar.zEntities[i].sFirstSawPlayer = gzTextVar.zEntities[i].sLocation
            gzTextVar.zEntities[i].sLastSawPlayer = gzTextVar.gzPlayer.sLocation
        
        --Can't see the player. Do nothing here.
        else
    
        end
    end
    
    --Stop the logic here.
    return
end

--[ ===================================== Catching Function ===================================== ]
--Called if the entity catches the player and initiates a battle.
fnStranger_CatchPlayer = function(i)
    
    --If the player is not a human, don't bother.
    if(gzTextVar.gzPlayer.sFormState ~= "Human") then return end
    
    --Player is surrendering.
    if(gzTextVar.bIsPlayerSurrendering == true) then
        LM_ExecuteScript(gzTextVar.sRootPath .. "AIs/CutsceneStranger/Surrender To Stranger.lua", i)
        return
    end
    
    --Dialogue.
    if(gzTextVar.bCombatActivatedThisTick == false) then
        gzTextVar.bCombatActivatedThisTick = true
        TL_SetProperty("Append", "The hulking brute catches up to you - defend yourself!" .. gsDE)
        TL_SetProperty("Create Blocker")
    
        TL_SetProperty("Exec Script", gzTextVar.sCombatHandler, 3, i, "Standard", "Standard")
    
    --Combat is active. Run the handler but not in queue.
    elseif(gzTextVar.bCombatActivatedThisTick == true) then
        TL_SetProperty("Exec Script", gzTextVar.sCombatHandler, 3, i, "Standard", "Standard")
    end
    
end

--[ ========================================= Normal AI ========================================= ]
--Main AI sequence.
fnStranger_AI = function(i)

    --Flag. Track the stranger's activity. It stops updating if the stranger is defeated.
    gzTextVar.iStrangerDefeatedTurn = gzTextVar.iWorldTurns

    --[ ========== Detection Handling ========== ]
    --[Same Room, Player Surrendering]
    --In the same room, player is surrendering.
    if(gzTextVar.zEntities[i].sLocation == gzTextVar.gzPlayer.sLocation and gzTextVar.gzPlayer.sFormState == "Human" and gzTextVar.bIsPlayerSurrendering == true) then
        LM_ExecuteScript(gzTextVar.sRootPath .. "AIs/CutsceneStranger/Surrender To Stranger.lua", i)
        return

    --[Same Room, Player Fights]
    --If in the same room, a battle will start.
    elseif(gzTextVar.zEntities[i].sLocation == gzTextVar.gzPlayer.sLocation or gzTextVar.bIsTriggeringFights) then
    
        --[Player Crippled]
        --If the player is crippled but has not been transformed yet:
        if(gzTextVar.gzPlayer.bIsCrippled == true and gzTextVar.gzPlayer.sFormState == "Human") then
            LM_ExecuteScript(gzTextVar.sRootPath .. "AIs/CutsceneStranger/Defeated by Stranger.lua", i)
            return
            
        --[Not Crippled, Battle]
        --Humans trigger a battle.
        elseif(gzTextVar.gzPlayer.sFormState == "Human") then
            fnStranger_CatchPlayer(i)
            return
        
        --Other cases, stranger ignores you.
        else
        
        end
    end

    --[ ========== Spot the Player ========== ]
    --Run the AI to check if we can see the player. If so, we don't bother checking doors.
    local bCanSeePlayer = false
    if(gzTextVar.gzPlayer.sFormState == "Human") then
        bCanSeePlayer = fnStandardAI_SpotPlayer(i)
    end

    --[ ========== Door Handling ========== ]
    local bClosedDoorThisTurn = fnStandardAI_HandleDoor(i)

    --[ ========== Movement Failure ========== ]
    --At this point, dolls have a 15% chance to simply not move for a turn. This makes them harder to
    -- predict and slightly easier to outrun. The chance decreases if they can see you.
    local iSkipRoll = LM_GetRandomNumber(1, 100)
    local iSkipChance = 15
    if(bCanSeePlayer) then iSkipChance = 10 end
    if(iSkipRoll <= iSkipChance) then
        return 
    end

    --[ ========== Spot-Player Logic ========== ]
    --Attempt to spot the player from our current location. If the player is more than 3 tiles away,
    -- don't bother running the spotter algorithm to save time.
    if(gzTextVar.gzPlayer.sFormState == "Human") then
        local bHandledUpdate = fnStandardAI_SpotChasePlayer(i, bCanSeePlayer, fnStranger_CatchPlayer)
        if(bHandledUpdate) then return end
    end

    --[ ========== Patrol Logic ========== ]
    --[Door Handler]
    --If a door was closed this turn, stop here.
    if(bClosedDoorThisTurn == true) then return end

    --[New Movement]
    --If the current movement index is -1, move to the next node on the patrol list.
    if(gzTextVar.zEntities[i].iMoveIndex == -1) then
        
        --[Staying Still]
        --Can be flagged to stay still if you want.
        if(gzTextVar.zEntities[i].iStayStillTurns > 0) then
            gzTextVar.zEntities[i].iStayStillTurns = gzTextVar.zEntities[i].iStayStillTurns - 1
            return
        end
        
        --Setup.
        local sPatrolTarget = "Nowhere"
        
        --[Get the Search Area]
        --First, no area. If the player is at "None", then the Stranger does not hunt them. The stranger
        -- instead searches the previous area, and will thus be nearby.
        local sUseGrouping = gzTextVar.zStranger.sPlayerCurrentGrouping
        if(sUseGrouping == "None") then sUseGrouping = gzTextVar.zStranger.sPlayerPreviousGrouping end
        
        --If the grouping is still "None", then that means the player hasn't entered any groupings. Use the first grouping.
        if(sUseGrouping == "None") then sUseGrouping = gzTextVar.zStranger.saGroupList[1] end
        
        --[Pick a Random Search Target]
        --Each search area has a list of locations the Stranger can search. It picks one at random and moves there.
        -- We can't search the same area twice in a row, so just reroll if that happens.
        for p = 1, #gzTextVar.zStranger.saGroupList, 1 do
            
            --Check if this is the grouping.
            if(gzTextVar.zStranger.zGroups[p].sGrouping == sUseGrouping) then
                
                --Error: The group has no entries:
                if(gzTextVar.zStranger.zGroups[p].iEntriesMax == 0) then
                    io.write("Warning: Stranger group " .. gzTextVar.zStranger.zGroups[p].sGrouping .. " has no entries.\n")
                    sPatrolTarget = "Main Hall"
                
                --Group has exactly one entry, so... search it really hard?
                elseif(gzTextVar.zStranger.zGroups[p].iEntriesMax == 1) then
                    gzTextVar.zEntities[i].sLastGroup = sUseGrouping
                    sPatrolTarget = gzTextVar.zStranger.zGroups[p].saRooms[1]
                
                --Roll.
                else
                
                    --Do the roll.
                    local iRolledRoom = LM_GetRandomNumber(1, gzTextVar.zStranger.zGroups[p].iEntriesMax)
                
                    --Check if this happens to be identical to the previous roll. If so, increase the number by 1 and search that room.
                    if(gzTextVar.zEntities[i].sLastGroup == sUseGrouping and gzTextVar.zEntities[i].iLastRoom == iRolledRoom) then
                        iRolledRoom = iRolledRoom + 1
                        if(iRolledRoom > gzTextVar.zStranger.zGroups[p].iEntriesMax) then iRolledRoom = 0 end
                    end
                    
                    --Search!
                    gzTextVar.zEntities[i].sLastGroup = sUseGrouping
                    gzTextVar.zEntities[i].iLastRoom = iRolledRoom
                    sPatrolTarget = gzTextVar.zStranger.zGroups[p].saRooms[iRolledRoom]
                    
                    --Debug.
                    --io.write("Stranger searches " .. gzTextVar.zStranger.zGroups[p].saRooms[iRolledRoom] .. "\n")
                end
                
                break
            end
            
        end

        --Store this as the pathing target.
        gzTextVar.zEntities[i].saPatrolList = {sPatrolTarget}

        --Make the first move in the direction in question.
        gzTextVar.zEntities[i].iMoveIndex = 1
        
        --Run the subroutine. This will move the entity if everything went well.
        --io.write("Moving to patrol target. " .. sPatrolTarget .. "\n")
        LM_ExecuteScript(gzTextVar.sRootPath .. "AIs/Standard Move To Destination.lua", i, sPatrolTarget)
            
        --Entity emits sound.
        local iDestIndex = fnGetRoomIndex(gzTextVar.zEntities[i].sLocation)
        if(iDestIndex ~= -1) then
            gzTextVar.zRoomList[iDestIndex].iLastHeardSound = gzTextVar.iWorldTurns
        end
        
        --If the destination was reached, reset the move handler.
        if(gzTextVar.zEntities[i].sLocation == sPatrolTarget) then
            gzTextVar.zEntities[i].iMoveIndex = -1
        end
        
        --Catch the player if we enter their tile.
        if(gzTextVar.zEntities[i].sLocation == gzTextVar.gzPlayer.sLocation) then
            fnStranger_CatchPlayer(i)
        end

    --Continuing a patrol path.
    else
        
        --Check if the patrol is invalid.
        if(gzTextVar.zEntities[i].saPatrolList == nil) then
            gzTextVar.zEntities[i].iMoveIndex = -1
            gzTextVar.zEntities[i].iPatrolIndex = 1
            gzTextVar.zEntities[i].saPatrolList = {"None"}
            return
        end
        
        --Variables.
        local sPatrolTarget = "Target"
        local sRoomName = gzTextVar.zEntities[i].sLocation
        local iRoomIndex = fnGetRoomIndex(sRoomName)
        
        --Get the target.
        sPatrolTarget = gzTextVar.zEntities[i].saPatrolList[1]
        
        --If the patrol target comes back as "Nowhere", then stop here and reset the search criteria.
        if(sPatrolTarget == "Nowhere") then
            gzTextVar.zEntities[i].iMoveIndex = -1
            return
        end
        
        --Run the subroutine. This will move the entity if everything went well.
        --io.write("Moving continue to patrol target. " .. sPatrolTarget .. ".\n")
        LM_ExecuteScript(gzTextVar.sRootPath .. "AIs/Standard Move To Destination.lua", i, sPatrolTarget)
            
        --Entity emits sound.
        local iDestIndex = fnGetRoomIndex(gzTextVar.zEntities[i].sLocation)
        if(iDestIndex ~= -1) then
            gzTextVar.zRoomList[iDestIndex].iLastHeardSound = gzTextVar.iWorldTurns
        end
        
        --If the destination was reached, reset the move handler.
        if(gzTextVar.zEntities[i].sLocation == sPatrolTarget) then
            gzTextVar.zEntities[i].iMoveIndex = -1
        end
        
        --Catch the player if we enter their tile.
        if(gzTextVar.zEntities[i].sLocation == gzTextVar.gzPlayer.sLocation) then
            fnStranger_CatchPlayer(i)
        end

    end
end