//:: Purpose:         Have a placeable or NPC "speak" when a trigger is touched.
//::
//:: Instructions:    Put down a trigger, and assign this script "cas_shatemple" on the OnEnter event of the script.
//::                  Assign the following variables:
//::
//::                  - int nMaxLines = the maximum number of "lines" on the placeable or NPC. This will tell it what number to stop at when randomly searching or speaking "in order"
//::                  - float fTimeBetweenText = the delay between lines of text being speaking. This is in seconds.
//::                  - float fMaximumTimeBeforeIReset = There is a timer on the trigger to prevent multiple people from triggering the event and spamming the dialogue box
//::                                                     with text. This is in seconds.
//::                  - string sSpeakingPlaceable = The Tag of the Placeable you want to speak. Make sure this is UNIQUE.
//::                  - string sSpeakingTag = The Tag of the NPC you want to speak. Make sure this is UNIQUE.
//::                  - int bSpeakInOrder = 0 = random, 1 = in order.
//::                  - string SpeakTextX = Assigned to the placeable or NPC, this tells the script what text to "speak." PUT THIS ON THE PLACEABLE OR NPC, NOT THE TRIGGER. X is the number.

// Constants
const string SPEAK_TEXT_VARNAME_PREFIX = "SpeakText";
const string SPEAK_PLACEABLE_TAG_VARNAME = "sSpeakingPlaceable";
const string SPEAK_NPC_TAG_VARNAME = "sSpeakingTag";
const string MAX_LINES_VARNAME = "nMaxLines";
const string AM_ACTIVATED_FLAG_VARNAME = "AmIActivated";
const string SPEAK_IN_ORDER_FLAG_VARNAME = "bSpeakInOrder";
const string TIME_BETWEEN_TEXT_VARNAME = "fTimeBetweenText";
const float COOLDOWN_TIME = 180.0f; // Cooldown time in seconds (3 minutes)

// Function to reset trigger activation state
void ResetTriggerActivation(object oTrigger) {
    SetLocalInt(oTrigger, AM_ACTIVATED_FLAG_VARNAME, FALSE);
}

// Function to speak a line from the placeable or NPC
void SpeakLine(object oSpeaker, int nMaxLines, int bSpeakInOrder, int nCurrentLine) {
    int nLine;
    string sVariableName, sLine;

    if(bSpeakInOrder == 1) {
        // Stop speaking if the last line has been reached
        if(nCurrentLine > nMaxLines) {
            return;
        }
        nLine = nCurrentLine;
    } else {
        nLine = Random(nMaxLines) + 1; // Random line
    }

    sVariableName = SPEAK_TEXT_VARNAME_PREFIX + IntToString(nLine);
    sLine = GetLocalString(oSpeaker, sVariableName);

    if(sLine != "") {
        AssignCommand(oSpeaker, SpeakString(sLine));
    }

    // Prepare for the next line
    if(bSpeakInOrder == 1) {
        nLine = nCurrentLine + 1; // Increment for the next line

        float fTimeBetweenText = GetLocalFloat(OBJECT_SELF, TIME_BETWEEN_TEXT_VARNAME);
        DelayCommand(fTimeBetweenText, SpeakLine(oSpeaker, nMaxLines, bSpeakInOrder, nLine));
    }
}

void main() {
    object oTrigger = OBJECT_SELF;
    object oSpeaker;
    int nMaxLines, bSpeakInOrder;
    string sSpeakingPlaceable = GetLocalString(oTrigger, SPEAK_PLACEABLE_TAG_VARNAME);
    string sSpeakingTag = GetLocalString(oTrigger, SPEAK_NPC_TAG_VARNAME);

    // Check if either the placeable or NPC tag is specified and if the trigger is already activated
    if((sSpeakingPlaceable == "" && sSpeakingTag == "") || GetLocalInt(oTrigger, AM_ACTIVATED_FLAG_VARNAME) == TRUE)
        return;

    // Set the trigger as activated
    SetLocalInt(oTrigger, AM_ACTIVATED_FLAG_VARNAME, TRUE);

    // Find the nearest placeable or NPC based on the specified tags
    if (sSpeakingPlaceable != "") {
        oSpeaker = GetNearestObjectByTag(sSpeakingPlaceable, oTrigger);
    } else if (sSpeakingTag != "") {
        oSpeaker = GetNearestObjectByTag(sSpeakingTag, oTrigger);
    }

    if (!GetIsObjectValid(oSpeaker)) return; // Ensure a valid object is found

    nMaxLines = GetLocalInt(oTrigger, MAX_LINES_VARNAME);
    if (nMaxLines <= 0) return; // Invalid number of lines

    bSpeakInOrder = GetLocalInt(oTrigger, SPEAK_IN_ORDER_FLAG_VARNAME);

    SpeakLine(oSpeaker, nMaxLines, bSpeakInOrder, 1); // Start from the first line

    // Reset trigger after the cooldown time
    DelayCommand(COOLDOWN_TIME, ResetTriggerActivation(oTrigger));
}
