View Full Version : global variables on server/npc?
spider661
07-01-2008, 06:03 PM
is there a way to set a variable on an npc or the server that other npcs can read?
i have a quest and players turn in an item and get ported to an area with a boss.. i need that boss to see how many players actually have the quest and how many don't then drop a amount of items so that all that have the quest get the items and all that don't. don't get the item so basically items drop ass needed and not jsut a set amount of 6 per say. sense it is a raid boss there could only be 1 player needing the item then there could be 20 players needing it.
Andrew80k
07-01-2008, 07:31 PM
After thinking about it a while I'm not sure you can do this. I can't come up with a way for the NPC to spawn with the right number of items. You might could use the quest::addloot(itemid,charges) function, but I'm not sure how the mob would know how many players in this particular group/raid actually had the quest. You could increment a global server wide that would track how many people on the server had the quest, but that wouldn't help you with a particular set of folks.
trevius
07-01-2008, 07:33 PM
You would be better off just setting the quest to use globals and then having an NPC spawn at the end of the fight for people to hail and get the new flag (global) if they have the quest started up to the point needed.
Changing loot tables with quests isn't easy. Though, there is another way you could do it if you really want it to be a dropped item. Basically, setup a quest NPC near the boss that will use the "quest::signalwith(212025,1,0);" command to the boss and have the boss use the "quest::addloot(2845,1);" quest command.
Here is an example from one of my quests that I adjusted to work for your case:
The Quest on the NPC that sends the signal to the boss to add loot:
sub EVENT_SAY {
if ($text =~/Hail/i) {
if (defined($qglobals{bossloot})) {
if ($qglobals{bossloot} == 1) {
quest::say("Hello, $name, I will get your loot added right away.");
$client->Message(15, "Your loot has been added to the boss.");
quest::signalwith(212025,1,0);
quest::setglobal("bossloot", 2, 5, "F"); }
if ($qglobals{bossloot} == 2) {
quest::say("You already have the loot added to this boss."); }
}
else {
quest::say("You need to begin the quest before we can speak further."); }
}
}
The Quest on the Boss NPC:
#NPCID 212025
sub EVENT_SIGNAL {
if ($signal == 1) {
quest::addloot(2845,1); }
}
That should give you someplace to start, though you might want to make more adjustments to how the globals work.
Striat
07-02-2008, 12:56 PM
You'd obviously need to use a busy script in their somewhere and maybe check entity list for that bosses id to make sure he is up. But, just focusing on the other thing, addloot should work okay last I checked. One way is to use GroupCount. I personally modded it abit on my server to check for names in entity list rather than a quick numeric scan. One problem you may run into is that GroupCount takes into consideration the amount of people in the group regardless of whether they are in the zone or not last I checked. So, say you have a group of 6. But only 2 in the zone. Well, it'd return 6 and thus loot for 6.
There is another way to get aggro and generate a loot counter based on that. I've experienced flaws with pets and how aggro is handled with them.
Another method would be to use player.pl. You could generate a counter that way even. You could then have a global set for boss loot. And used group id as a global and have player.pl check if you're grouped against that group id to port you to the location. And then have a signal to the npc to addloot from the player file. I'll try to post an example later if you run into a problem. I would do it this way if possible to avoid potential error.
A revision including the groupcount could be:
sub EVENT_SAY {
my $bossmob = $entity_list->GetMobByNpcTypeID(212025);
if ($text =~/Hail/i) {
if (!$busy && $bossmob) {
quest::say("Hello, $name, are you [interested] in my challenge?.");
}
else {
quest::say("Sorry, I cannot help you at this time.");
}
}
if ($text =~/interested/i) {
if (!$busy && $bossmob) {
my $group = $client->GetGroup();
if ($group) {
my $loot = $group->GroupCount();
}
else {
my $loot = 1;
}
quest::movegrp();
quest::signalwith(212025,$loot,0);
}
else {
quest::say("Sorry, I cannot help you at this time.");
}
}
}
The Quest on the Boss NPC:
#NPCID 212025
sub EVENT_SIGNAL {
quest::addloot(2845,$signal);
}
Thats a starting point. You'd need to adjust the engaged/not engaged as well as busy variable and removing loot from an encounter when he is not engaged.
spider661
07-02-2008, 04:25 PM
ok i got a quest working using the timers to lock the zone on the npc that sends you there. basically you talk to him he sends you to the zone and gives you 2 mins to bring friends then when you kill the bos it spawns a npc and the npc flags you as done. but i want to lock the zone off for 2 hours per fight. but it seems when the zone closes and despawns with the first npc in it then someone comes in and talks to that npc again it still sends you to the zone becuase the npc was respawned and the variables on him cleared.. is there a way to save and read them from the database or something? so it will not send the players to the zone till he is suppose to. or even a way to actually lock the zone till then?
Andrew80k
07-02-2008, 04:57 PM
You could despawn him when you have the group setup, like you do now but only have him respawn when the npc that flags everyone tells him to respawn. And if you have the only way in to the zone limited to that NPC, you essentially lock everyone else out. Say your flagging NPC has to be told "Ready" or "Return" or something when everyone is done, then you zone everyone in the group and then respawn the quest npc. At least that's an approach you could take. There are likely others...
spider661
07-02-2008, 05:54 PM
the problem with that is if the zone despawns how do i tell the npc not to spawn and to spawn..
i know how to dopop the npc but then when the zone goes down and comes back up then the npc will be back again.
thats the problem the zone is dynamic. i could set it to static but then if it crashes it comes back up as dynamic and i have the same problem. and all it takes is for one player to find out how to crash the zone and then they can get into the other zone and wait around for however to do all the work then walk up and hail the npc that flags them.
trevius
07-02-2008, 06:41 PM
When I want to block players from getting flags that others have earned, I just use a deathguard or a proximity banisher to block anyone some accessing the section of the zone that the flag is attained from. There are many ways to spawn the guards, but I normally use either EVENT_ATTACK, Timers, or an NPC that the players have to speak with to tell the event to start. Once that happens, the NPC or the Boss spawns some NPCs that will block off the path to reach that area of the zone.
You can look at the Vox/Naggy scripts for good proximity quests that will move a player to another zone, or somewhere else in the same zone to prevent them from making it to the flag NPC. You can also spawn guards that hit for 32K with insane attack speeds, good agro ranges, and very high Accuracy and Attack Ratings. Then, just have the guards on the same faction so that they will share agro and have them close enough so that they do. I normally set 1 guard to run very fast and the other to be perma-rooted. That way, people can't just have a monk pull both of the guards out of the way so others can get through. Even if they can make it past the rooted guard, they will get agro from the running one as soon as it gets back to within range of the rooted one for agro to share.
If I really want to make sure players don't pass an area of a zone, I will use both proximity banishers and death guards together and then players don't stand much of a chance in making it through. That is because there is a slim chance that a FD class could make it past the guards and FD without getting killed, but adding the proximity banisher in there will keep that from happening. Make sure the death guards see invis, ITU, as well as hide and improved hide as well to keep rogues out.
If you do that, then you shouldn't have to worry much about locking the zone to keep others out.
If you are making an encounter that only requires a max of 1 single group, you could also use the move group quest command to move the entire group to the flagging area that is blocked off and then you could skip the part of having to spawn the death guards and proximity banisher. You could have it so that the first group to speak with the group teleporting NPC will get moved and then have the teleporter depop for 2 hours
There are quite a few ways you can come up with to keep others from getting flags without having to lock out the whole zone.
spider661
07-02-2008, 08:44 PM
i dont think the death guards or proximities wold work becuase of the zone size. the zone the npc 1 sends you 2 is "loading" so its just a very small room with one boss spawned there.
i did have a thought though
how hard would it be to add a new quest command copy the setglobal and get globals and customize them to write to a new table setting a server wide variable that an npc could read.
would i just have to add a new line to questmgr.cpp copying the old and adding to it or would i have to change 200 other files to get it to work?
Striat
07-03-2008, 04:36 PM
i dont think the death guards or proximities wold work becuase of the zone size. the zone the npc 1 sends you 2 is "loading" so its just a very small room with one boss spawned there.
i did have a thought though
how hard would it be to add a new quest command copy the setglobal and get globals and customize them to write to a new table setting a server wide variable that an npc could read.
would i just have to add a new line to questmgr.cpp copying the old and adding to it or would i have to change 200 other files to get it to work?
To add a command, you'd have to do some edits to questmgr.cpp, questmgr.h, perlparser.cpp. I think questmgr even tells you steps you would need to follow. However, I do not think it is necessary. Just use player quests. Basically, have the npc set a global and then port. Say you want 2 hours. Use kind of what I have written. Get groupID for the group and have it set the groupid as a global. then, in the zone the player zones into, have it check for that global. This may need some editing, but here is an idea that should work.
Event_Giver.pl
sub EVENT_SAY {
$groupid = undef;
my $group = $client->GetGroup();
$a = $client->GetName();
if($text=~/Hail/i){
quest::say("Hello, $a. Are you [interested] in a trial?");
}
if($text=~/interested/i){
if ($group) {
$groupid = $group->GetID();
$groupcount = $group->GroupCount();
quest::say("Very, well, $name. My records show that you have a total of $groupcount members in your group. Any attempts to add additional members AFTER entering the event will result in immediate disqualification. Therefore, make sure your group is completely set up before saying ready. When you are [ready], we shall begin.");
}
else {
quest::say("My records show you that you are not in a group, $name. You may enter an event without a group, but I strongly discourage it. If you still wish to enter, just sat when you are [ready].");
}
}
if($text=~/ready/i){
if ($qglobals{eventready} == 1) {
quest::say("Sorry, there is currently an event occurring. You will need to wait a few minutes.");
}
else {
if ($group) {
$groupid = $group->GetID();
$groupcount = $group->GroupCount();
quest::say("Then get ready!");
quest::delglobal("eventcontender");
quest::delglobal("eventcontendersize");
quest::delglobal("eventready");
quest::setglobal("eventcontender",$groupid,7,"F");
quest::setglobal("eventcontendersize",$groupcount,7,"F");
quest::setglobal("eventready",1,7,"F");
quest::movegrp(); #ADD YOUR INFO HERE
}
}
}
}
And this script would actually go in the folder where the event is located.
player.pl
sub EVENT_ENTERZONE {
$a = undef;
$group = $entity_list->GetGroupByClient($client);
$a = $client->GetName();
$client->SetHeading(128);
quest::settimer("checkaccess", 1);
if ($group) {
$groupid = $group->GetID();
}
if ($qglobals{eventready}) {
if ($group && $qglobals{eventcontender} == $groupid) {
$client->Message(15, "Your event will begin in less than a minute!");
}
elsif ($a eq "$qglobals{eventcontender}") {
$client->Message(15, "Your event will begin in less than a minute!");
}
else {
$client->Message(15, "You are not allowed access to this zone, $a!");
quest::movepc(202,460,378,-128);
}
}
else {
$client->Message(15, "You are not allowed access to this zone, $a!");
quest::movepc(202,460,378,-128);
}
}
sub EVENT_TIMER {
$group = $entity_list->GetGroupByClient($client);
$a = $client->GetName();
if ($group) {
$groupid = $group->GetID();
$groupcount = $group->GroupCount();
}
if ($timer eq "checkaccess") {
if ($qglobals{eventready}){
if ($group) {
if ($groupid != $qglobals{eventcontender}) {
$client->Message(15, "You are not allowed access to this zone, $a!");
quest::movepc(202,460,378,-128);
}
elsif ($groupcount > $qglobals{eventcontendersize}) {
$client->Message(15, "You have illegally added members to your group!");
quest::movepc(202,460,378,-128);
}
}
elsif (!$group && $a ne "$qglobals{eventcontender}") {
$client->Message(15, "You are not allowed access to this zone, $a!");
quest::movepc(202,460,378,-128);
}
}
}
}
AndMetal
07-06-2008, 01:09 AM
is there a way to set a variable on an npc or the server that other npcs can read?
is there a way to save and read them from the database or something?
how hard would it be to add a new quest command copy the setglobal and get globals and customize them to write to a new table setting a server wide variable that an npc could read.
What you're trying to do it already in the source. All you have to do it utilize the options when you set a global. From the Wiki (http://www.eqemulator.net/wiki/wikka.php?wakka=QuestTutorial):
quest::setglobal([varname],[value],[options],[duration]);
Command Parameters
[varname] the name of the variable you want to save. Do not include the variable prefix as part of the name. When the quest for the npc who recieves this variable begins, a variable with the name that you here preceeded by a "$" will be available. For example, if [varname] is "genius" then a variable named $genius will be available to the quest script of the npc with whatever you specified in it. Variables are cached and won't be reloaded unless the cache cleared or the variable is undefined. So make sure to use $variable = undef; after the variable was used, especially if you have multiple persons using the quest.
[value] this is what the variable will contain when the quest script begins.
[options] value determines the availability of global variables to NPCs when a quest begins -- this way you can decide what mobs can "see" the variable.
[duration] the amount of time this variable will be available. After this time, the variable goes away!
Example for option:
-----------------------------------------
| value | npcid | player | zone |
-----------------------------------------
| 0 | this | this | this |
| 1 | all | this | this |
| 2 | this | all | this |
| 3 | all | all | this |
| 4 | this | this | all |
| 5 | all | this | all |
| 6 | this | all | all |
| 7 | all | all | all |
-----------------------------------------
In other words, the following values can be ORed together:
NPC_ALL = 1
PLAYER_ALL = 2
ZONE_ALL = 4
Example: NPC_ALL | PLAYER_ALL = 3
In other words, use 1 instead of 0 and all NPCs will be able to read the quest global.
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.