//:: nw_casino_math_start.nss
//:: Placeable OnUsed - starts math game + spawns clickable fish placeables

const string TOKEN_TAG           = "I_CAS_CASINOHANDLE";
const string VAR_DIFFICULTY      = "INT_DIFFICULTY";

const string FISH_RESREF         = "casino_fish";
const string WAYPOINT_TAG_PREFIX = "iSpawnFishHere";
const int    TOTAL_WAYPOINTS     = 10;

const int    DESIRED_FISH_COUNT  = 3;
const float  MIN_FISH_LIFETIME   = 2.0;
const float  MAX_FISH_LIFETIME   = 10.0;

// -------------------- helpers --------------------

void DespawnFish(object oFish)
{
    if (GetIsObjectValid(oFish))
    {
        DestroyObject(oFish);
    }
}

void CleanupOwnedFish(object oPC)
{
    object oArea = GetArea(oPC);
    object oObj  = GetFirstObjectInArea(oArea);
    while (GetIsObjectValid(oObj))
    {
        if (GetObjectType(oObj) == OBJECT_TYPE_PLACEABLE &&
            GetResRef(oObj) == FISH_RESREF &&
            GetLocalObject(oObj, "FISH_OWNER") == oPC)
        {
            DestroyObject(oObj);
        }
        oObj = GetNextObjectInArea(oArea);
    }
}

int CountOwnedFish(object oPC)
{
    int nCount   = 0;
    object oArea = GetArea(oPC);
    object oObj  = GetFirstObjectInArea(oArea);
    while (GetIsObjectValid(oObj))
    {
        if (GetObjectType(oObj) == OBJECT_TYPE_PLACEABLE &&
            GetResRef(oObj) == FISH_RESREF &&
            GetLocalObject(oObj, "FISH_OWNER") == oPC)
        {
            nCount++;
        }
        oObj = GetNextObjectInArea(oArea);
    }
    return nCount;
}

int IsOwnedFishAtLocation(object oPC, location lLoc, float fRadius)
{
    int nShape = SHAPE_SPHERE;
    int bLOS   = FALSE;
    int nType  = OBJECT_TYPE_PLACEABLE;

    object oCheck = GetFirstObjectInShape(nShape, fRadius, lLoc, bLOS, nType);
    while (GetIsObjectValid(oCheck))
    {
        if (GetResRef(oCheck) == FISH_RESREF &&
            GetLocalObject(oCheck, "FISH_OWNER") == oPC)
        {
            return TRUE;
        }
        oCheck = GetNextObjectInShape(nShape, fRadius, lLoc, bLOS, nType);
    }
    return FALSE;
}

void SpawnFishForPlayer(object oPC)
{
    if (!GetIsObjectValid(oPC) || !GetIsPC(oPC) || GetIsDM(oPC))
        return;

    // Stop spawning if the run ended
    if (!GetLocalInt(oPC, "MATH_GAME_ACTIVE"))
        return;

    // Keep at least DESIRED_FISH_COUNT alive
    if (CountOwnedFish(oPC) >= DESIRED_FISH_COUNT)
        return;

    int iTries = 10;
    while (iTries > 0)
    {
        int iWP = Random(TOTAL_WAYPOINTS) + 1;
        string sWPTag = WAYPOINT_TAG_PREFIX + IntToString(iWP);
        object oWP = GetWaypointByTag(sWPTag);

        if (!GetIsObjectValid(oWP))
        {
            iTries--;
            continue;
        }

        location lSpawn = GetLocation(oWP);

        // If a fish for THIS PC is already here, try a different waypoint
        if (IsOwnedFishAtLocation(oPC, lSpawn, 1.0))
        {
            iTries--;
            continue;
        }

        int nFishValue = Random(10); // 0..9
        object oFish = CreateObject(OBJECT_TYPE_PLACEABLE, FISH_RESREF, lSpawn);
        if (!GetIsObjectValid(oFish))
            return;

        SetName(oFish, IntToString(nFishValue));
        SetLocalInt(oFish, "FISH_VALUE", nFishValue);
        SetLocalObject(oFish, "FISH_OWNER", oPC);

        // Despawn after random time in [2..10] seconds
        float fDelay = IntToFloat(Random(9) + 2);
        DelayCommand(fDelay, DespawnFish(oFish));

        // After it despawns, try to top up again
        DelayCommand(fDelay + 0.2, SpawnFishForPlayer(oPC));
        return;
    }
}

// -------------------- main --------------------

void main()
{
    object oPC = GetLastUsedBy();

    if (!GetIsPC(oPC) || GetIsDM(oPC))
        return;

    object oToken = GetItemPossessedBy(oPC, TOKEN_TAG);
    if (!GetIsObjectValid(oToken))
    {
        SendMessageToPC(oPC, "You need a casino token to play.");
        return;
    }

    int nDifficulty = GetLocalInt(oToken, VAR_DIFFICULTY);
    if (nDifficulty < 1 || nDifficulty > 3)
    {
        SendMessageToPC(oPC, "Set difficulty on your token first (1-3).");
        return;
    }

    // Prevent re-start spam (optional)
    if (GetLocalInt(oPC, "MATH_GAME_ACTIVE"))
    {
        SendMessageToPC(oPC, "Game already running. Click fish to play.");
        return;
    }

    // Start run
    int nTarget = Random(100); // 0..99
    SetLocalInt(oPC, "MATH_GAME_TARGET", nTarget);
    SetLocalInt(oPC, "MATH_GAME_CURRENT", 0);
    SetLocalInt(oPC, "MATH_GAME_ACTIVE", 1);

    // Clean any leftover owned fish (in case of crash/reload)
    CleanupOwnedFish(oPC);

    SendMessageToPC(oPC, "Target number: " + IntToString(nTarget));

    // Spawn initial batch (define loop var outside the loop)
    int i;
    for (i = 0; i < DESIRED_FISH_COUNT; i++)
    {
        SpawnFishForPlayer(oPC);
    }
}
