Author Topic: How to trigger a world event- at random intervals.  (Read 661 times)

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
How to trigger a world event- at random intervals.
« on: June 14, 2011, 10:27:43 am »


               Ok,
Basically, I am making a system where planar portals can spawn in any area of my module, chosen at random, with random elemental affinity, which the players can then participate in, as a Rift Raid etc.


I've got most of the important things worked out.

1 - Picking the Area at random from a list of areas with criteria of Outdoors, Above Ground, and Natural (this is to avoid City and Market places) - Done
2. Spawning of the Planar Tear (which is phase 1 of the rift) - Non-Hostile. - In progress, still to be tested. Turning the randomly chosen location in the area, to a valid spawn location for a placeable has been somewhat troublesome.



Anyway, my major concern is...
How do I randomly generate these without supervision?



I am using nwnx, with mySQL Functionality, which is how I get the random area. (select from areas where interior = 0 and natural = 1 and aboveground = 1 order by rand() limit 1).

I also believe I could use the
Select UNIX_TIMESTAMP()  along with adding the desired cooldown time to that, to get the next spawn time.


Im just wondering if there is any better way of doing it?


eg -  Would you use your modules Heartbeat?


I pretty much want to have 30 minutes for the minimum time between rifts, and 5 hours maximum.
Random(18000) + 1800 
Random Number between 0 and 5 hours, plus 30 minutes.
Would this be enough?
               
               

               
            

Legacy_CID-78

  • Sr. Member
  • ****
  • Posts: 261
  • Karma: +0/-0
How to trigger a world event- at random intervals.
« Reply #1 on: June 14, 2011, 01:09:33 pm »


               Well i would have a Time Queue running on the Module Heartbeat. which can handle a diverse number of event such as this one, and any event that isn't almost immediatly excuted. such as timed quests
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
How to trigger a world event- at random intervals.
« Reply #2 on: June 14, 2011, 05:16:01 pm »


               It seems to me that you could solve the "random location within an area problem" by setting way points that have a certain amount of clearance around them, say 5 meters. If you have more than one in the area, you would use the same tag but add an integer at the end.

The script that places the rift would select one of the way points in the area, and pick a random point within 5 meters of the way point.
               
               

               


                     Modifié par henesua, 14 juin 2011 - 04:16 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
How to trigger a world event- at random intervals.
« Reply #3 on: June 14, 2011, 05:28:39 pm »


               Yes, you should use your mod heartbeat, for timestamping. Once you have a timestamping setup, you can use it as a low-impact command-delay mechanism that is much more cpu-efficient than actual delaycommands. 

Boot time is recorded on modload:


    /*  load boot time into the boottime variable */
    SQLExecDirect("SELECT UNIX_TIMESTAMP()");

    if (SQLFetch() == SQL_SUCCESS) {
        string sBootTime = SQLGetData(1);
        string sServerAddr = FileReadAll("serveraddr.txt");
        string sServerPort = FileReadAll("serverport.txt");

        if (StringToInt(sServerPort) < 5000)
            sServerPort = "512" + IntToString(nServerNumber % 10);

        SetLocalInt(oMod, "boottime", StringToInt(sBootTime));
        SetLocalString(oMod, "ServerAddr", sServerAddr);
        SetLocalString(oMod, "ServerPort", sServerPort);

        SQLExecDirect("REPLACE INTO server_list (srv_id, srv_btime, srv_utime, srv_memory, srv_players, srv_addr, srv_port, srv_last) VALUES ('"
                      + sServerNumber + "', " + sBootTime + ", 0, 0, 0, '" + sServerAddr + "', " + sServerPort + ", NOW())");
    }

    SetLocalInt(oMod, "uptime", 0);

Uptime is then calculated from the mod heartbeat:


    SQLExecDirect("SELECT UNIX_TIMESTAMP() - " + sBootTime + ", UTC_TIMESTAMP(), UNIX_TIMESTAMP(), " +
        "COUNT(*) FROM user_messages WHERE um_recipient = '*" + sServer + "'");

    if (SQLFetch() == SQL_SUCCESS) {
        nUptime = StringToInt(SQLGetData(1));
        nMessages = StringToInt(SQLGetData(4));

        SetLocalInt(oMod, "uptime", nUptime);
        SetLocalInt(oMod, "realtime", StringToInt(SQLGetData(3)));
        SetLocalString(oMod, "utctime", SQLGetData(2));

        SQLExecDirect("UPDATE server_list SET srv_utime = " + IntToString(nUptime) + ", srv_memory = " +
            IntToString(nMemory) + ", srv_players = " + IntToString(nPlayers) + " WHERE srv_id = '" + sServer + "'");

        SQLExecDirect("SELECT COUNT(*) FROM user_list WHERE u_active > 0");
        if (SQLFetch() == SQL_SUCCESS)
            SetLocalInt(oMod, "GlobalPlayers", StringToInt(SQLGetData(1)));

        SQLExecDirect("SELECT COUNT(*) FROM user_list WHERE u_active > 0 AND u_server_name REGEXP '" + GetStringLeft(sServer, 1) + ".[1-8]'");
        if (SQLFetch() == SQL_SUCCESS) {
            int nHubPlayers = StringToInt(SQLGetData(1));

            SetLocalInt(oMod, "HubPlayers", nHubPlayers);

            if (GetStringLeft(sServer, 1) != "1" && GetStringRight(sServer, 1) == "1")
                SetNumberOfPlayers(nHubPlayers);
        }
    }

Much more accurate than simply incrementing. Note that a lot of the above code is linked to our interserver messaging and other functionality - the setting of the time ints is the critical part.

You can then use that to set timestamped events. By way of example, we despawn areas to prevent unkilled critters from lagging up the server, among other reasons, but wanted to prevent abuse. Doing so required tracking times and respawning loot and such only after a set interval, when the encounters would also be back. Done with delaycommands, it would mean hundreds or even thousands of delays running modwide, depending on traffic. Done with timestamps, it means nothing running until it needs to be checked. Our areas are checked when a player enters them, and reset if necessary:


    /* respawn loot or other other respawnables */
    nSpawns = GetLocalInt(oArea, "Area_Respawns");

    if (nSpawns > 0) {
        int i, nType, nRespawnTime, nUptime = GetLocalInt(GetModule(), "uptime");
        string sKey, sVar;
        object oSpawn;

        for (i = 1; i <= nSpawns; i++) {
            sKey = IntToString(i);

            nRespawnTime = GetLocalInt(oArea, "Area_Respawn_" + sKey);
            if (nRespawnTime <= 0 ||
                nRespawnTime > nUptime ||
                GetIsObjectValid(GetLocalObject(oArea, "Area_Respawn_Obj_" + sKey)))
                continue;

            oSpawn = CreateObject(GetLocalInt(oArea, "Area_Respawn_Type_" + sKey),
                GetLocalString(oArea, "Area_Respawn_Res_" + sKey),
                GetLocalLocation(oArea, "Area_Respawn_Loc_" + sKey));

            SetLocalObject(oArea, "Area_Respawn_Obj_" + sKey, oSpawn);

            if ((sVar = GetLocalString(oArea, "Area_Respawn_Var_" + sKey)) != "")
                AssignCommand(oArea, DelayCommand(0.0, RestoreLocals(oSpawn, sVar)));
        }
    }

    /* clear despawn setting on area */
    if (GetLocalInt(oArea, "DespawnTrack")) {
        int nDespawnTime = GetLocalInt(oArea, "DespawnTime");
        if (nDespawnTime) {
            int nUptime = GetLocalInt(GetModule(), "uptime");
            if ((nUptime - 3600) > nDespawnTime) {
                DeleteLocalInt(oArea, "DespawnTime");
                DeleteLocalInt(oArea, "DespawnCount");
            }
        }
    }

Funky