[Question] Calling a Script

I’m currently writing a spawn system that will spawn 1 NPC at a time, based on a timer, and will spawn that NPC to a random player but only if a: The player is in a certain area and b: When the player has a toggled value set to true. I’ve got the guts of the code working, that is testing if a player is in a certain polygonal area and has the toggle set to true.

My main questions then are

A: Where might I put the code for the timer that will trigger the spawn system every, lets say, 30 minutes?

B: How could I make the aforementioned spawn system in a Custom/scriptname.cpp script?

C: Are there better methods for getting information from the database then WorldDatabase.Query()?

Basically: If I had the Trigger Timer, when it reaches 30 minutes, I want it to grab a list of players, check each player if they have the Spawn Toggle set to true and are in a certain area. Then add the ones with true to both of those into an array. Then randomly grab one of those players in that array, call a script that will check their zone, grab a random NPC that fits in that zone and spawn it in front of them. Reset the timer.

I can write all the code myself, I just haven’t quite gotten the TrinityCore structure down pat and need a nudge in the right direction.

Here is the relevant code.

Located in - Player.cpp Player::Update()

if(GetDynamicSpawningState() == true && hasSpawnedDebugTest == false)
hasSpawnedDebugTest = true; //only call once while debugging.
This is the method Player::DynamicSpawnNPC(), also inside of the Player class. This is the method that I want to move into it’s own script if possible. I was looking into how other scripts get called but I wasn’t sure about PlayerScripts or hooks because it didn’t seem like the right/best method of doing it.

void Player::DynamicSpawnNPC()
Field* fields;
std::vector ids;
uint16 id;
Player* p = this;
if(m_isInWater == false || IsUnderWater() == false)
QueryResult result = WorldDatabase.Query(“SELECT id, zone FROM ds_creature”);
fields = result->Fetch();
id = fields[0].GetUInt16();
uint16 zone = fields[1].GetUInt16();
if(zone == GetZoneIdFromDB(GetGUID()))
id = ids[0]; // Will make this random chosen based on size, but for debug purposes, just using the first item in the array.
p->SummonCreature(id, GetPositionX(), GetPositionY(), GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3600000);
Also to note that, whenDynamicSpawnNPC() gets called

p->SummonCreature(6, GetPositionX(), GetPositionY(), GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3600000);
doesn’t execute in game, although

Say(“Spawning NPC”, LANG_UNIVERSAL);
does execute. I figure I am doing something wrong?

Here is the code toggle command code, to set the DynamicSpawningState variable to either true or false.


A: You can use the updateAI’s diff to calculate the 30 minutes and then run the script when the time is up.

See example_creature.cpp for the creature timers (cast spells) and use the same idea with worldscript and it’s update.

Alternatively you could try using EventMap in the same update hook.

For example see : http://pastebin.com/3aNVhK4e

B: Code it in one? The script system works through classes that you can code to the custom cpp of your’s and then you just add a function that creates the object in scriptloader.cpp.

IE: use the worldscript class and it will work through the custom cpp.

C: Yes and no. You cant access the database in other ways, but you could load the database data to the memory and keep it stored during the run of the program.

Then when you need the data, you dont need to query the database, just get it from the memory. You will probably need some sort of container (UNORDERED_MAP, vector, list, map …) if you dont want to make a core mod.

(I mean that you could also add the var to the classes that use the vars, IE Player class)

The code you got there seems like you set the boolean to true for the players on update and then just check if it is true when you run the script every 30 minutes.

This doesnt sound so good, since there is useless spamming of setting the variable. You could just check if the players are in the area when running the script (every 30 min), instead of every update (every 50~300 ms).

Additionally, you could create a trigger NPC in the location that has an event every update or something that checks the players around instead of running the thing for everyone on every update. (It would run only when someone is around the NPC’s sight)

In the query you could use PQuery (incase you cant find a good way to avoid querying …)
You can add additional arguments to PQuery and include the zone requirement to the query. This would avoid the zone check (less looping)

You should probably check if the result is something (not NULL) also check that there is an entry (no row matched the zone from the returned rows → crash)
Have you tested if the code (summoning) is actually run at all? Try printing

I suspect the DB data or the water checks.

Alright, I will take this all into careful consideration, thank you for the help. Yea, I figured the way I was trying to do it was sloppy and might have a lot of unnecessary loops and calls, but thats why I came to ya’ll! And as for the code (summoning) I forgot to mention that, when I was testing it, I used

Say(“Spawning NPC”, LANG_UNIVERSAL);

to test and it would run in game.

So I’ll go apply some of these changes and I may or may not stop by if I run into anything else I can’t figure out! Thank you a bunch!