Go Back   EQEmulator Home > EQEmulator Forums > Quests > Quests::Q&A

Quests::Q&A This is the quest support section

Reply
 
Thread Tools Display Modes
  #1  
Old 08-01-2009, 11:46 AM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Thumbs up Wandering NPC qglobal

I have a qglobal set up to spawn an npc in certain zones. The idea is that he starts off in one zone, stays for a set length of time, depops and repops in a different zone, and repeats that process continuously. For purposes of illustration, I'll narrow it to Zone 1, Zone 2, and Zone 3.

The npc spawns in Zone 1, whereupon the script immediately deletes the previous global variable (1) and sets a new one (2). The timer keeps him in the zone for 2 minutes (again, just to simplify), and when he depops he respawns in Zone 2, deletes the previous variable (2) and sets the new variable (3). The process repeats and when he gets to Zone 3 the script deletes the previous variable and sets it at variable 1 again, and it repeats that entire sequence.

I have global watchers in each of the three zones that define under which variable condition they will spawn the npc. Both scripts appear below (these are the scripts for Zone 1):
Code:
#Wanderer NPC -- npcid 999228

sub EVENT_SPAWN
	{
	quest::delglobal("wanderer");
	quest::setglobal("wanderer", 2, 7, "F");
	quest::shout("I am now in the zone");
	quest::settimer("depop",120);
	}

sub EVENT_TIMER
	{
	if($timer eq "depop")
		{
		quest::shout("I am now leaving the zone");
		quest::stoptimer("depop");
		quest::depop();	
		}
	}
Code:
my $EventStart;

sub EVENT_SPAWN 
	{
	$EventStart = 0;
	quest::depopall(999228);
	}

sub EVENT_WAYPOINT
	{
	quest::shout("");

	if (defined($qglobals{wanderer})) 
		{

		my $x;
		my $y;
		my $z;
		my $h;

		$x = $npc->GetX();
		$y = $npc->GetY();
		$z = $npc->GetZ();
		$h = $npc->GetHeading();		

		if ($qglobals{wanderer} == 1 && $EventStart == 0)
			{	
			$EventStart == 1;
			quest::spawn2(999228,0,0,$x+5,$y+5,$z,$h);
			}
		}

	}
The script works fine but for one or two details. First, there's really nothing in place to start the sequence of events. Second, I'm not convinced the placement of the delglobal and setglobal is actually workable in a real-world scenario, and I'm not sure the alternative is either.

The first issue first. In order to start it I have to manually add the global to the db to get the npc to spawn initially. If I don't add it manually each time I boot up the server, the watchers will never see a variable and therefore will never spawn the npc.

There are several "fixes" that I've already thought through or tried and dismissed, including:

1. Dbspawn the wanderer in Zone 1 so that the global sets when a player enters that zone. I tried this but found that the wanderer would respawn in that same zone (Zone 1) whenever a player exited and reentered the (empty) zone, even though the npc was already spawned in Zone 2.

2. Use an event on a third npc to trigger the global initially (such as EVENT_SAY hail). But then the global would reset each time another player hails the npc.

Now for the second issue--placement of the delglobal and setglobal. The current placement deletes the global and resets it to the next variable immediately upon spawning the npc. Here it is . . .

sub EVENT_SPAWN
{
quest::delglobal("wanderer");
quest::setglobal("wanderer", 2, 7, "F");
quest::shout("I am now in the zone");
quest::settimer("depop",120);
}

However, if I want the npc to remain in each zone for an hour, and if the new global variable (new spawn zone) is set at the beginning of that hour, then the npc could potentially be in two zones at one time--he'll stay in Zone 1 (if populated by a pc) until he depops, but since the global has neen reset, he'll also appear in Zone 2 if a pc enters that zone at the same time.

So, I tried placing the setglobal with the depop timer event, like so:

sub EVENT_SPAWN
{
quest::delglobal("wanderer");
quest::shout("I am now in the zone");
quest::settimer("depop",120);
}

sub EVENT_TIMER
{
if($timer eq "depop")
{
quest::setglobal("wanderer", 2, 7, "F");
quest::shout("I am now leaving the zone");
quest::stoptimer("depop");
quest::depop();
}
}

However, if the wanderer pops in a zone that is populate by a pc, and the pc leaves before the depop occurs, then the new global is never set. And since the old global has been deleted, there is nothing for the watchers to see that would cause a subsequent spawn.

Then I tried putting both the delglobal and the setglobal in the depop timer event, like so:

sub EVENT_SPAWN
{
quest::shout("I am now in the zone");
quest::settimer("depop",120);
}

sub EVENT_TIMER
{
if($timer eq "depop")
{
quest::delglobal("wanderer");
quest::setglobal("wanderer", 2, 7, "F");
quest::shout("I am now leaving the zone");
quest::stoptimer("depop");
quest::depop();
}
}

However, when I do this the watcher spawns another npc every five seconds (watchers are on a 5-sec grid). I assumed the $EventStart object (which works perfectly in another global) would prevent this, but it hasn't (unless I am doing something wrong with it).

In any case, these are the issues I am having. I need the wandering npc to (1) initially spawn apart from a manual process, (2) be a unique character in the world, (3) be in only one zone at a time, (4) wander from zone to zone continually.

Any help would be most appreciated.
Reply With Quote
  #2  
Old 08-01-2009, 01:14 PM
joligario's Avatar
joligario
Developer
 
Join Date: Mar 2003
Posts: 1,497
Default

How about this:

Add the NPC to all zones using the spawn point at where it would enter the zone. In EVENT_SPAWN, have it check if the global is set to a number associated with the current zone. If it is not, then depop(). If it is, do a start() and when it reaches a specific x/y, have it stop(). Set the global for the next zone, and run a depop().

Other things to consider if using this method:
Designate 1 "start" zone. When that NPC spawns, have it set its own zone number in the global if the global does not exist. If killed, ensure the global is deleted in EVENT_DEATH. If a zone crashes, no big deal, because the global is already set for that specific zone, so it will just start over at the beginning of its path only in that zone.
Reply With Quote
  #3  
Old 08-01-2009, 01:40 PM
Dibalamin
Hill Giant
 
Join Date: Dec 2007
Posts: 182
Default

Or you can make it be random by using another set of globals.
__________________
Retired EMarr
Project1999 Developer
Reply With Quote
  #4  
Old 08-01-2009, 08:23 PM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Default

Joli, I think you suggested having the global check and depop as part of the npc script; but wouldn't it be better placed in the watcher script, as follows?
Code:
sub EVENT_WAYPOINT
	{
	if (defined($qglobals{wanderer})) 
		{

		my $x;
		my $y;
		my $z;
		my $h;

		$x = $npc->GetX();
		$y = $npc->GetY();
		$z = $npc->GetZ();
		$h = $npc->GetHeading();		

		if ($qglobals{wanderer} == 1 && $EventStart == 0)
			{	
			$EventStart == 1;
			quest::spawn2(999228,0,0,$x+5,$y+5,$z,$h);
			}
		elsif ($qglobals{wanderer} != 1)
			{
			quest::depop(999228);
			}
		}
	}
Would this accomplish the same thing?
Reply With Quote
  #5  
Old 08-01-2009, 08:52 PM
joligario's Avatar
joligario
Developer
 
Join Date: Mar 2003
Posts: 1,497
Default

Well, what I was suggesting does not require a "watcher". Basically, the NPC(s) would look at the 1 global and decide whether or not it should stay spawned. I'll give you an example in a few minutes.
Reply With Quote
  #6  
Old 08-01-2009, 09:50 PM
joligario's Avatar
joligario
Developer
 
Join Date: Mar 2003
Posts: 1,497
Default My Example

Create an NPC (we'll say Wanderer) with whatever stats you want, but enable qglobals.
In spawn2 table, set a spawn at 100% at the zone-in location from the previous zones (each of which, we'll call 1, 2, and 3). For example, zone2 spawn point would be where Wanderer would have zoned in from zone1. Zone3 spawn would be from the zone line of zone2, and zone1 would be from the zone line of zone3.
Create waypoints (we'll say id of 100) in our zones. Use full pause and ensure that the last waypoint has a decent pause time for the x/y check.

All 3 script files will look almost identical. Items in red will be the difference between the files. The first one is the starting zone.

quests\1\Wanderer.pl
Code:
my $ZoneOutX = 1111;
my $ZoneOutY = 1111;

sub EVENT_SPAWN {
  if (!defined($qglobals{Wanderer}) {
    quest::setglobal("Wanderer",1,7,"F");
  }
  if (defined($qglobals{Wanderer}) && ($qglobals{Wanderer} == 1)) {
    quest::start(100);
  }
  else {
    depop();
  }
}

sub EVENT_DEATH {
  quest::delglobal("Wanderer");
}

sub EVENT_WAYPOINT {
  if (($x == $ZoneOutX) && ($y == $ZoneOutY)) {
    quest::stop();
    quest::setglobal("Wanderer",2,7,"F");
    quest::depop();
  }
}
quests\2\Wanderer.pl
Code:
my $ZoneOutX = 2222;
my $ZoneOutY = 2222;

sub EVENT_SPAWN {
  if (defined($qglobals{Wanderer}) && ($qglobals{Wanderer} == 2)) {
    quest::start(100);
  }
  else {
    depop();
  }
}

sub EVENT_DEATH {
  quest::delglobal("Wanderer");
}

sub EVENT_WAYPOINT {
  if (($x == $ZoneOutX) && ($y == $ZoneOutY)) {
    quest::stop();
    quest::setglobal("Wanderer",3,7,"F");
    quest::depop();
  }
}
quests\3\Wanderer.pl
Code:
my $ZoneOutX = 3333;
my $ZoneOutY = 3333;

sub EVENT_SPAWN {
  if (defined($qglobals{Wanderer}) && ($qglobals{Wanderer} == 3)) {
    quest::start(100);
  }
  else {
    depop();
  }
}

sub EVENT_DEATH {
  quest::delglobal("Wanderer");
}

sub EVENT_WAYPOINT {
  if (($x == $ZoneOutX) && ($y == $ZoneOutY)) {
    quest::stop();
    quest::setglobal("Wanderer",1,7,"F");
    quest::depop();
  }
}
Reply With Quote
  #7  
Old 08-02-2009, 09:55 PM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Default

I've tested each part of this script, and this part of it is broken:

if (!defined($qglobals{Wanderer}) {
quest::setglobal("Wanderer",1,7,"F");
}

The rest of it works fine. Any reason this part doesn't work? Is the ! being used correctly?
Reply With Quote
  #8  
Old 08-02-2009, 10:05 PM
joligario's Avatar
joligario
Developer
 
Join Date: Mar 2003
Posts: 1,497
Default

Yeah, I missed a close parenthesis.

Code:
if (!defined($qglobals{Wanderer})) {
That's what I get for writing code "on the fly" instead of testing it first.
Reply With Quote
  #9  
Old 08-02-2009, 10:22 PM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Default

Bah! I'm ashamed I missed that! It appears to be working now. Just need to revamp the 2d and 3d script and try the whole sequence. I'll let you know how it goes. Thanks.
Reply With Quote
  #10  
Old 08-03-2009, 12:18 AM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Default

Okay, the following part is not working:

Code:
sub EVENT_WAYPOINT 
	{
 	if (($x == $ZoneOutX) && ($y == $ZoneOutY)) 
		{
    		quest::stop();
		quest::delglobal("wanderer");
   		quest::setglobal("wanderer",2,7,"F");
    		quest::depop();
  		}
	}
The npc is not responding to anything in this event. I assumed I should change the previously defined ZoneOuts from 1111 to the actual xy coords of the final waypoint, like so:

my $ZoneOutX = -15972.6;
my $ZoneOutY = 632.1;

Is this correct?
Reply With Quote
  #11  
Old 08-03-2009, 08:27 PM
joligario's Avatar
joligario
Developer
 
Join Date: Mar 2003
Posts: 1,497
Default

Yes.

Now, in the database, do you have that exact location in the grid_entries as the last grid for his path in that zone? If so, there might be a possibility that he triggers the waypoint before he gets to that exact coordinate. Also, just in case, are you sure the x/y y/x is correct?
Reply With Quote
  #12  
Old 08-03-2009, 09:31 PM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Default

It is the exact location as in grid_entries. And I used #loc on the npc when he was paused at the final waypoint to verify the coords (x comes first using #). Those values are in the definition:

my $ZoneOutX = -15972.6;
my $ZoneOutY = 632.1;

The zone is Qey2hh1 and is on the dirt path right before the zone line with northkarana.
Reply With Quote
  #13  
Old 08-03-2009, 09:55 PM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Default

Just out of curiosity, in the WAYPOINT event, shouldn't I be using eq instead of == since technically it's a string?

sub EVENT_WAYPOINT
{
if (($x == $ZoneOutX) && ($y == $ZoneOutY))
{
Reply With Quote
  #14  
Old 08-03-2009, 11:41 PM
neiv2
Hill Giant
 
Join Date: Mar 2009
Location: CO
Posts: 183
Default

That wasn't it. Doesn't work either way.

My other theory is that sub EVENT_WAYPOINT is a relatively recent addition and that my version of the server code simply does not recognize it (I know that's the case with quest::we, which does not work in my world).
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 03:49 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3