--[ =================================== Doll Tutorial Patrol ==================================== ]
--Doll AI that patrols. When it catches the player, they are warped back to a certain room.

--[ ====================================== Hostility Checker ==================================== ]
--AI is checking whether it is hostile to the player.
fnDollTutPatrol_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.
fnDollTutPatrol_PostTurnSpotCheck = function(i)
    
    --[Non-Human]
    --If the player is not a human, don't bother.
    if(gzTextVar.gzPlayer.sFormState ~= "Human") then return end

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

    --[Movement Handlers]
    --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. Dolls path 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
end


--[ ===================================== Catching Function ===================================== ]
--Called if the entity catches the player and initiates a battle.
fnDollTutPatrol_CatchPlayer = function(i)
    
    --Tutorial defeat handler.
    TL_SetProperty("Append", "You got caught! We'll move you back a bit. Hide in side rooms and close the door.")
    TL_SetProperty("Create Blocker")
    TL_SetProperty("Append", "You can close doors with the [close] or [close n/s/e/w] command, or by clicking the door on the game map.")
    TL_SetProperty("Create Blocker")
    TL_SetProperty("Append", "As the enemy moves nearby, you can see the sound they make on the map. Figure out the patrol and move when the enemy is far away.")
    TL_SetProperty("Create Blocker")
        
    --Setup.
    local sDestination = "Extended Hall S"
    local fOldX, fOldY, fOldZ = fnGetRoomPosition(gzTextVar.gzPlayer.sLocation)
    local fX, fY, fZ = fnGetRoomPosition(sDestination)

    --Unmark the previous location, and mark this one as visible.
    fnUnmarkMinimapForPosition(gzTextVar.gzPlayer.sLocation)
    fnMarkMinimapForPosition(sDestination)

    --Move the character.
    gzTextVar.gzPlayer.sPrevLocation = gzTextVar.gzPlayer.sLocation
    gzTextVar.gzPlayer.sLocation = sDestination
    TL_SetProperty("Set Map Focus", -fX, -fY)

    --Change the indicator's position.
    TL_SetProperty("Move Entity Indicator", fOldX, fOldY, fOldZ, "Player", fX, fY, fZ)
    TL_SetProperty("Player World Position", fX, fY, fZ)
    fnRebuildEntityVisibility()
    fnBuildLocalityInfo()
end

--[ ========================================= Normal AI ========================================= ]
--Main AI sequence.
fnDollTutPatrol_AI = function(i)
    
    --[ ========== 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
        fnDollTutPatrol_CatchPlayer(i)
        return

    --[Same Room, Player Hostile]
    --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
            fnDollTutPatrol_CatchPlayer(i)
            return
        
        --[Crippled, Blank Doll]
        --Player is a blank doll. Dolls carry the player for dressing.
        elseif(gzTextVar.gzPlayer.bIsCrippled == true and gzTextVar.gzPlayer.sFormState == "Blank Doll") then
        
            --We need to move toward's Pygmalie's location, which is the Main Hall in stage 1.
            local sRoomName = gzTextVar.zEntities[i].sLocation
            local iRoomIndex = fnGetRoomIndex(sRoomName)
            
            --Get the target room.
            local iTargetIndex = fnGetRoomIndex(gzTextVar.zEntities[gzTextVar.iPygmalieIndex].sLocation)
            
            --Error checks.
            if(iRoomIndex == -1 or iTargetIndex == -1) then
                return
            end
            
            --Get the first letter of matching movement.
            local sPathInstructions = gzTextCon.zRoomList[iTargetIndex].zPathListing[iRoomIndex]
            if(sPathInstructions == "") then
                return
            end
            local sFirstLetter = string.sub(sPathInstructions, 1, 1)
        
            --Move in the requested direction:
            local sDestination = "Null"
            if(sFirstLetter == "N") then
                sDestination = gzTextVar.zRoomList[iRoomIndex].sMoveN
                if(gzTextVar.zRoomList[iRoomIndex].sDoorN ~= nil and string.sub(gzTextVar.zRoomList[iRoomIndex].sDoorN, 1, 1) == "C") then
                    LM_ExecuteScript(gzTextVar.sRootPath .. "Functions/Modify Door State.lua", gzTextVar.gzPlayer.sLocation, "O Normal", "N", ciModifyVisibility, 0)
                    AudioManager_PlaySound("Doll|OpenDoor")
                end
            elseif(sFirstLetter == "S") then
                sDestination = gzTextVar.zRoomList[iRoomIndex].sMoveS
                if(gzTextVar.zRoomList[iRoomIndex].sDoorS ~= nil and string.sub(gzTextVar.zRoomList[iRoomIndex].sDoorS, 1, 1) == "C") then
                    LM_ExecuteScript(gzTextVar.sRootPath .. "Functions/Modify Door State.lua", gzTextVar.gzPlayer.sLocation, "O Normal", "S", ciModifyVisibility, 0)
                    AudioManager_PlaySound("Doll|OpenDoor")
                end
            elseif(sFirstLetter == "E") then
                sDestination = gzTextVar.zRoomList[iRoomIndex].sMoveE
                if(gzTextVar.zRoomList[iRoomIndex].sDoorE ~= nil and string.sub(gzTextVar.zRoomList[iRoomIndex].sDoorE, 1, 1) == "C") then
                    LM_ExecuteScript(gzTextVar.sRootPath .. "Functions/Modify Door State.lua", gzTextVar.gzPlayer.sLocation, "O Normal", "E", ciModifyVisibility, 0)
                    AudioManager_PlaySound("Doll|OpenDoor")
                end
            elseif(sFirstLetter == "W") then
                sDestination = gzTextVar.zRoomList[iRoomIndex].sMoveW
                if(gzTextVar.zRoomList[iRoomIndex].sDoorW ~= nil and string.sub(gzTextVar.zRoomList[iRoomIndex].sDoorW, 1, 1) == "C") then
                    LM_ExecuteScript(gzTextVar.sRootPath .. "Functions/Modify Door State.lua", gzTextVar.gzPlayer.sLocation, "O Normal", "W", ciModifyVisibility, 0)
                    AudioManager_PlaySound("Doll|OpenDoor")
                end
            elseif(sFirstLetter == "U") then
                sDestination = gzTextVar.zRoomList[iRoomIndex].sMoveU
            elseif(sFirstLetter == "D") then
                sDestination = gzTextVar.zRoomList[iRoomIndex].sMoveD
            end

            --Failure:
            if(sDestination == "Null") then
                return
            end
            
            --Move indicators.
            local fOldX, fOldY, fOldZ = fnGetRoomPosition(gzTextVar.zEntities[i].sLocation)
            local fX, fY, fZ = fnGetRoomPosition(sDestination)
            TL_SetProperty("Move Entity Indicator", fOldX, fOldY, fOldZ, gzTextVar.zEntities[i].sIndicatorName, fX, fY, fZ)

            --Success! Move the character.
            fnUnmarkMinimapForPosition(gzTextVar.gzPlayer.sLocation)
            gzTextVar.zEntities[i].sLocation = sDestination
            fnMarkMinimapForPosition(sDestination)
            
            --Move the player as well.
            gzTextVar.gzPlayer.sPrevLocation = gzTextVar.gzPlayer.sLocation
            gzTextVar.gzPlayer.sLocation = sDestination
            TL_SetProperty("Set Map Focus", -fX, -fY)
            TL_SetProperty("Move Entity Indicator", fOldX, fOldY, fOldZ, "Player", fX, fY, fZ)
            TL_SetProperty("Player World Position", fX, fY, fZ)
            TL_SetProperty("Reresolve Fades")

            --Rendering handler. Top floor renders the middle floor, otherwise no secondary rendering.
            TL_SetProperty("Set Rendering Z Level", fZ)
            if(fZ < 0) then
                TL_SetProperty("Set Under Rendering Z Level", fZ+1, 0)
            else
                TL_SetProperty("Set Under Rendering Z Level", ciDoNotRenderUnder, ciDoNotRenderUnder)
            end

            --Show the room's name, list of entities, and objects.
            TL_SetProperty("Append", gzTextVar.zEntities[i].sDisplayName .. " carries you to " .. sDestination .. "." .. gsDE)
            fnListEntities(gzTextVar.gzPlayer.sLocation, true)
            fnListObjects(gzTextVar.gzPlayer.sLocation, true)
            return
        
        --[Not Crippled, Battle]
        --Humans trigger a battle.
        elseif(gzTextVar.gzPlayer.sFormState == "Human") then
            fnDollTutPatrol_CatchPlayer(i)
            return
        
        --Other cases, doll 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, fnDollTutPatrol_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
    
    --[Run Logic]
    fnStandardAI_Patrol(i, fnDollTutPatrol_CatchPlayer)
end
