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 05-25-2008, 04:32 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default Clearing Quest Globals

I have been trying to get this issue fixed for some time on my server. It seems like an odd issue to me, but no matter what I try so far, it doesn't seem to resolve the issue.

So, the problem is with my new level 71 - 75 levels which are gained via quests. It seems that the globals of the character with the highest global gets saved in the quest somehow so that the next person who attempts the quests will get the global of the previous person without actually having done any of the work. I know that I have to set the global as undef and I think I have tried doing that in just about every way I can think of and all of them still have this weird effect.

The ranks of my globals are supposed to match the level of what the player should be for max level. So, even though players can only experience up to level 70, they can still quest for levels up to 75. I think have a couple of quests that I use these globals in to keep track of what max level the player should be. So, a player with a max_level global of 73 has earned up to level 73 via the quests.

Well, here is the main quest I am having an issue with. It is my delevel quest with added stuff for access to a special zone and also added stuff for the level 71+ levels. The important section in question is highlighted in red, but I am posting the whole thing incase it is needed to help resolve the issue.

Code:
#Quest to de-level a character temporarily in exchange For an item
#that can be turned in to return to level 70

sub EVENT_SAY {

if(($text=~/hail/i)&&($ulevel <= 69)) {
quest::say("Hello, $name, I have an interesting deal for you, but you must reach 70 seasons before I can make my offer.  Please return to me when you reach level 70.  If you are here to return my trinket, please do so and I will restore your experience."); }

if(($text=~/hail/i)&&($ulevel >= 70)) {
quest::say("Hello, $name, I can lower your [level] temporarily if you would like.  It is useful if you have friends that are lower level and would like to group with them, but don't want to make a new character and start over.  If your friends are level 51+, you can group with them and work on AAs that will carry over when you return to level 70."); }

if(($text=~/level/i)&&($ulevel >= 70)) {
quest::say("The way it works is I take your experience from you and give you a trinket in exchange.  When you are ready to go back to level 70 again, simply turn in the trinket to me and I will return your experience.  Would you like to know the level [ranges] I can set you to?  I can also tell you about some [issues] you may encounter when you lower your level."); }

if(($text=~/ranges/i)&&($ulevel >= 70)) {
quest::say("I can set you to level [70], [65], [60], [55], [52], [51], [50], [45], [40], [35], [30], [25], [20], [15], [10], [5], or all of the way back to level [1].  Just let me know which level you would like to return to."); }

if(($text=~/70/i)&&($ulevel >= 71)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(70);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/65/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(65);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/60/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(60);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/55/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(55);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/52/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(52);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/51/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(51);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/50/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(50);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/45/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(45);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/40/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(40);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/35/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(35);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/30/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(30);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/25/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(25);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/20/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(20);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/15/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(15);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/10/i)&&($ulevel >= 70)){
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(10);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/^5$/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(5);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/^1$/i)&&($ulevel >= 70)) {
    quest::say("Here you go!  Remember, DO NOT lose that trinket!  You will need it to turn into me when you want to restore your level back to 70.  If you lose it, you will have to level up the normal way all over again!");
$client->Message(6, "Rayna Levya casts a spell and before you know it, you feel young and vibrant again.  The world suddenly seems much larger and more intimidating!");
quest::summonitem(1659);
quest::level(1);
quest::selfcast(331);
quest::setglobal("temp_level", 1, 5, "F"); }

if(($text=~/dragons/i)&&($ulevel >= 53)) {
$client->Message(0, "Rayna Levya whispers to you, Oh, so it is the great dragons you seek?  Well, you can't likely fight them like that!  They refuse to fight anyone who is too much of a threat and will [banish] you if you try.") }
 
if(($text=~/banish/i)&&($ulevel >= 53)) {
$client->Message(0, "Rayna Levya whispers to you, If you absolutely must battle the dragons, I can assist you by stealing your experience and returning you to level [52].  You can get the experience back from me whenever you like by returning the item I give you. Ask about the dragons again when you are the right level.") }
 
if(($text=~/dragons/i)&&($ulevel <= 52)) {
$client->Message(0, "Rayna Levya whispers to you, There!  Now you are ready to travel to their [dungeons] whenever you wish.  I can also tell you more about some [issues] with your new level as well.") }
 
if(($text=~/dungeons/i)&&($ulevel <= 52)) {
$client->Message(0, "Rayna Levya whispers to you, There are 2 great dragons that you should seek in this epic quest, and when you are ready, just ask to be sent to either the dungeon of [fire] or the dungeon of [ice].") }
 
if($text=~/issues/i) {
    quest::say("The main issue is that any item above your level will show you as giving the proper stats, but they are lying.  You gain no stats from items above your level and monsters are invulnerable to all attacks by weapons above your level.  So, you will want to use a set of equipment and weapons that are useable at the level you currently are. Do you want to hear the [other] issue?"); }
 
if($text=~/other/i) {
    quest::say("The other issues is that once you are returned to level 70, you will have lost any previous experience gained into that level and have to regain it again the hard way."); }
 
if ($text =~/fire/i) {
quest::say ("Good luck on your fight!");
$client->Message(6, "Rayna Levya creates a small ball of fire in her hands and you can feel your temperature rise as everything fades to black.");
quest::movepc(32, -824.1,-1273.2,86.2); }

if ($text =~/ice/i) {
quest::say ("Off ya go!");
$client->Message(6, "Rayna Levya starts breathing heavily and you begin to see the frost of her breath and then only darkness.");
quest::movepc(73, -32.1,1019,3.1); }

$temp_level=undef;
 
}


sub EVENT_ITEM {

 if (plugin::check_handin(\%itemcount, 1659 => 1)){

if ($max_level == 71) {
quest::say("Looks like you took good care of it!  Here are your levels back.");
$client->Message(6, "Rayna Levya casts a spell and you instantly feel more powerful!  The rush makes you feel like you could take on anything in battle!");
quest::level(71);
quest::setglobal("temp_level", 2, 5, "F"); }

if ($max_level == 72) {
quest::say("Looks like you took good care of it!  Here are your levels back.");
$client->Message(6, "Rayna Levya casts a spell and you instantly feel more powerful!  The rush makes you feel like you could take on anything in battle!");
quest::level(72);
quest::setglobal("temp_level", 2, 5, "F"); }

if ($max_level == 73) {
quest::say("Looks like you took good care of it!  Here are your levels back.");
$client->Message(6, "Rayna Levya casts a spell and you instantly feel more powerful!  The rush makes you feel like you could take on anything in battle!");
quest::level(73);
quest::setglobal("temp_level", 2, 5, "F"); }

if ($max_level == 74) {
quest::say("Looks like you took good care of it!  Here are your levels back.");
$client->Message(6, "Rayna Levya casts a spell and you instantly feel more powerful!  The rush makes you feel like you could take on anything in battle!");
quest::level(74);
quest::setglobal("temp_level", 2, 5, "F"); }

if ($max_level == 75) {
quest::say("Looks like you took good care of it!  Here are your levels back.");
$client->Message(6, "Rayna Levya casts a spell and you instantly feel more powerful!  The rush makes you feel like you could take on anything in battle!");
quest::level(75);
quest::setglobal("temp_level", 2, 5, "F"); }

if ($max_level == undef) {
quest::say("Looks like you took good care of it!  Here are your levels back.");
$client->Message(6, "Rayna Levya casts a spell and you instantly feel more powerful!  The rush makes you feel like you could take on anything in battle!");
quest::level(70);
quest::setglobal("temp_level", 2, 5, "F"); }

$max_level=undef;
  
 }

 	else {
 	    plugin::return_items(\%itemcount);
    	quest::say("I have no use for this item, $name.  Take it back.");
	} 
	
}
The problem here is that if a person who has earned level 75 uses this NPC to delevel and then level back up, the NPC will store the level 75 as the level to return all players to. So, any level 70 can delevel and turn in the item and instantly be 75. You can see where this would be annoying to me and my players... The odd thing is that if at that point they use the delevel quest again and turn the item in again, it will return them to their normal level that they should be according to their max_level global rank, which as a level 70 they would have none, so it would be undef.

I just can't figure out why it would send everyone back to a higher level even though it should have set the max_level global as undefined.

If I have to, I would be willing to depop and repop this NPC. Whatever it takes to get this quest working without the stupid bugs.

Also, here is my main quest leveling quest which is having a related problem:

Code:
sub EVENT_SAY {
if($text=~/hail/i)
{
quest::say("Hello, $name.  I am a card collector and am willing to trade my personal experience for cards.  If you have [minor], [godly] or the normal [card] of experience, I may be able to make a trade with you. I can also [return] your level if you have the correct status with me.");
}
if (($text =~/minor/i)&&($ulevel <= 44))
{
quest::say ("You must gain more experience before you can turn in this type of card to me.  I hear they are attained in the Plane of Earth B.");
}
if (($text =~/minor/i)&&($ulevel >= 45))
{
quest::say ("If you happen to come across any Cards of Minor Experience, please bring them to me and I will kindly reward you. I am creating a collection and can always use more.  Make sure to hand them to me unstacked.  I hear they are attained in the Plane of Earth B.");
}

if (($text =~/card/i)&&($ulevel <= 64))
{
quest::say ("You must gain more experience before you can turn in this type of card to me.  I hear they are attained in the Plane of Valor.");
}
if (($text =~/card/i)&&($ulevel >= 65))
{
quest::say ("If you happen to come across any Cards of Experience, please bring them to me and I will kindly reward you. I am creating a collection and can always use more.  Make sure to hand them to me unstacked.  You must be 65+ for me to reward you for these cards.");
}

if (($text =~/godly/i)&&($ulevel <= 69))
{
quest::say ("You must gain more experience before you can turn in this type of card to me.  I hear they are attained in the Tower of Solusek Ro.");
}
if (($text =~/godly/i)&&($ulevel >= 70))
{
quest::say ("If you happen to come across any Cards of Godly Experience, please give 4 of them to me at once and I will kindly reward you. I hear they are attained in the Tower of Solusek Ro. Make sure to hand them to me unstacked.");
}
if (($text =~/return/i)&&($ulevel <= 69))
{
quest::say ("You must be at least level 70 for me to provide this service to you!  Return when you have gained more experience.");
}

if (($text =~/return/i)&&($ulevel >= 70)) {

if ($max_level == 71) {
    quest::say("You are now set back to your previous maximum level.");
    quest::level(71); }

if ($max_level == 72) {
    quest::say("You are now set back to your previous maximum level.");
    quest::level(72); }

if ($max_level == 73) {
    quest::say("You are now set back to your previous maximum level.");
    quest::level(73); }

if ($max_level == 74) {
    quest::say("You are now set back to your previous maximum level.");
    quest::level(74); }

if ($max_level == 75) {
    quest::say("You are now set back to your previous maximum level.");
    quest::level(75); }
   
if ($max_level == undef){
    quest::say("You are already at your current maximum level."); }
   
$max_level=undef;
    
  }

}

sub EVENT_ITEM {

if ((plugin::check_handin(\%itemcount, 2275=>1))&&($ulevel >= 65)){
    quest::say("I am always looking for more for my collection.");
$client->Message(6, "Maximus Serilious rewards you with experience." );
    quest::exp(9999999); }
    
if ((plugin::check_handin(\%itemcount, 2834=>1))&&($ulevel >= 45)){
    quest::say("I am always looking for more for my collection.");
$client->Message(6, "Maximus Serilious rewards you with experience." );
    quest::exp(2000000); }
  
if (plugin::check_handin(\%itemcount, 2835=>4)) {
    
if ($max_level == 71) {
    quest::say("These are in excellent shape!  They will be trophies in my collection!");
$client->Message(6, "Maximus Serilious rewards you with a new level!" );
    quest::exp(9999999);
    quest::setglobal("max_level", 72, 5, "F");
    quest::level(72); }
    
if ($max_level == 72) {
    quest::say("These are in excellent shape!  They will be trophies in my collection!");
$client->Message(6, "Maximus Serilious rewards you with a new level!" );
    quest::exp(9999999);
    quest::setglobal("max_level", 73, 5, "F");
    quest::level(73); }
    
if ($max_level == 73) {
    quest::say("These are in excellent shape!  They will be trophies in my collection!");
$client->Message(6, "Maximus Serilious rewards you with a new level!" );
    quest::exp(9999999);
    quest::setglobal("max_level", 74, 5, "F");
    quest::level(74); }
    
if ($max_level == 74) {
    quest::say("These are in excellent shape!  They will be trophies in my collection!");
$client->Message(6, "Maximus Serilious rewards you with a new level!" );
$client->Message(15, "You have reached the max level!  Repeating this quest will give no further rewards!" );
    quest::exp(9999999);
    quest::setglobal("max_level", 75, 5, "F");
    quest::level(75); }

if ($max_level == 75) {
    quest::say("You have already reached the max level.  I can no longer reward you for the Cards of Godly Experience.  But if you want to give them to me anyway, I will take them for free. Ha ha ha!");
    quest::level(75); }
 	
if ($max_level == undef) {
    quest::say("These are in excellent shape!  They will be trophies in my collection!");
$client->Message(6, "Maximus Serilious rewards you with a new level!" );
    quest::exp(9999999);
    quest::setglobal("max_level", 71, 5, "F");
    quest::level(71); } 	
 	
$max_level=undef;
    
}
   
else {
 	 plugin::return_items(\%itemcount);
	 }
	
}
This quest will remember the global reward of the last person to turn in the 4 items. So, if the last person was level 75, then anyone who turns in the 4 items will become 75, even if they were just level 70 and should have become 71.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #2  
Old 05-25-2008, 04:52 AM
Gonner
Fire Beetle
 
Join Date: Aug 2007
Location: Columbus Grove, Ohio
Posts: 22
Default

Now while I am unsure of the exact cause of this issue have you tried to set your globals for "temp_level" a bit differ.. Like each level above 70 have a differ number. 71 be temp_level, 2, 5, F then level 72 be temp_level, 3, 5, F It may require a full rewrite of some quests but that may work.

The only reason i say this is your $max_level has the same variable for Undef and for each level. That is just from a quick look at the script and not a full eval of it.

Also quest::deglobal is how you remove gloabls. Had to pound that in my head recently as some of the quest I am working on kind of require it.
__________________
The reason I talk to myself is because I am the only one whose answers I accept.
Reply With Quote
  #3  
Old 05-25-2008, 10:08 AM
Bulle
Hill Giant
 
Join Date: Jan 2008
Posts: 102
Default

Your post triggered the "WEIRD" warning to me Trevius, so I spent a while today to look into it. I would like my conclusions to be validated by other EQEmu "hackers", so take them with the adequate grain of salt, but here they are.

To make it short I have two news : one good and one bad.
The good one is that there is a solution to your problem : switch from "$max_level" to "$qglobals{max_level}", supposedly the up-to-date way of checking quest globals. For all your variables, no exception.
The bad one is : checking quest globals through the use of "$XXX" variables is bugged. This is especially bad for PEQ quests, because there are a lot that work this way.

I have tried to reproduced your way of working on one NPC (the guard in the room in front of Neriak entrance, DVin L`Crit, who had qglobal set to 1 of course). Here is the code :
Code:
my $LevelItemId = 1038; # Tattered Cloth Sandal
my $DefaultMaxLevel = 70;

sub EVENT_SAY
{ print $maxxx_level;

  if(($text=~/65/i) && ($ulevel >= 70))
  { quest::say("Remember, DO NOT lose that trinket ! Welcome to level 65 !");
    quest::summonitem(1038);
    quest::level(65);
  }
  
  if($text=~/make me level 71/i)
  { quest::say("OK, you're the boss after all *sigh*");
    quest::level(71);
    quest::setglobal("maxxx_level", 71, 5, "F");
  }
  
  if($text=~/make me level 72/i)
  { quest::say("OK, you're the boss after all *sigh*");
    quest::level(72);
    quest::setglobal("maxxx_level", 72, 5, "F");
  }
  
  if($text=~/make me level 73/i)
  { quest::say("OK, you're the boss after all *sigh*");
    quest::level(73);
    quest::setglobal("maxxx_level", 73, 5, "F");
  }
  
  if($text=~/make me level 74/i)
  { quest::say("OK, you're the boss after all *sigh*");
    quest::level(74);
    quest::setglobal("maxxx_level", 74, 5, "F");
  }
  
  if($text=~/make me level 75/i)
  { quest::say("OK, you're the boss after all *sigh*");
    quest::level(75);
    quest::setglobal("maxxx_level", 75, 5, "F");
  }
}


sub EVENT_ITEM
{ if (plugin::check_handin(\%itemcount, $LevelItemId => 1))
  { if(defined($qglobals{maxxx_level}))
    { quest::say("Welcome back to level $qglobals{maxxx_level}, $name");
      quest::level($qglobals{maxxx_level});
    }
    else
    { quest::say("Welcome back to level $DefaultMaxLevel, $name");
      quest::level($DefaultMaxLevel);
    }
  }
  else
  { plugin::return_items(\%itemcount);
    quest::say("I have no use for this item, $name.  Take it back.");
  } 
}
Yeah I have used tattered sandals for the levelling item, I have been a fisher on Live for too long

As it is there is no side-effects across PCs. If you replace the $qglobals{maxxx_level} by $maxxx_level there is a side-effect from one PC to another if the PC has no $maxxx_level set for himself. Basically if your PC already has a maxxx_level (of say 72) Perl will use it. If the PC has never done your quest and set the $maxxx_level, then it uses the one the NPC has seen last, ie the variable is not reset to "undef". May be this is why you tried to "undef" it, but I did not try this, and from your experience it does not work that well. My experience is that the Emu does not "undef" a variable (which answers a question I had a few months ago in fact).

I had a quick look at the C++ code in the server, and it confirmed my suspicions : the "$qglobal" map is created anew each time the NPC evaluates its scripts (in fact for each event), it is a C++ variable globhash that is redeclared, hence reinitialized with each call. This is not the case for the $variables, which are only overwritten with new values. They are not undef'ed first (file embparser.cpp, lines 189+), there is no call to something reinitializing the Perl local/global environment, if it were at all possible anyway.

I see only two ways to address this :
* everybody switches to $qglobals{XXX} and we forget about the old "unperfect" bugged way. It has been hinted at for a long time, but I guess legacy quests slowed this to a halt.
* the C++ code is fixed to clean the Perl environment of all "stale" variables from a previous call to the event before the new one is run. It may be impossible (or very hard and unclean) to do.

As it is though, the problem may impact PEQ quests as it is general. Finding an example of a "broken" behaviour may be tough, but the potential is there. Think "exploit" here.

It would be nice if a developer or a PEQ maintainer could express their views on the subject.

As to me, I will be switching to $qglobals for my generated quest code.

I hope this long diatribe clears it up for you.
Reply With Quote
  #4  
Old 05-25-2008, 04:44 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

AHHH, so if I am understanding you correctly, it is saving the qglobal as a variable and that is why it is being carried over when other PCs do the quest if they don't have a global already defined? That explains why it only does it 1 time per PC instead of everytime they repeat the de-level and turn in process to re-level. That makes sense to me now, so thanks for the explanation! I didn't realize I was doing it the old way and that there are problems with doing it that way.

Now I have a whole new way to attempt to get this working flawlessly. So far my players seem to like the variety that being able to de-level adds in. This problem has been a thorn in my side for a while now lol. The fix you presented is a fairly simple one for me, since I only have maybe 10 or so qglobals in use on my server. Though, if PEQ had to change all of it's quests involving globals, that might present more of a problem.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #5  
Old 05-25-2008, 05:11 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Quote:
Originally Posted by Gonner View Post
Now while I am unsure of the exact cause of this issue have you tried to set your globals for "temp_level" a bit differ.. Like each level above 70 have a differ number. 71 be temp_level, 2, 5, F then level 72 be temp_level, 3, 5, F It may require a full rewrite of some quests but that may work.

The only reason i say this is your $max_level has the same variable for Undef and for each level. That is just from a quick look at the script and not a full eval of it.

Also quest::deglobal is how you remove gloabls. Had to pound that in my head recently as some of the quest I am working on kind of require it.
Didn't see this post at first. The temp_level global is for another quest and is unrelated to the problem I have been having. I have some fairly tricky globals in use for de-leveling and access to my de-level zone to ensure there are no possible exploits to gain access to the zone.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #6  
Old 05-25-2008, 05:41 PM
Bulle
Hill Giant
 
Join Date: Jan 2008
Posts: 102
Default

To explain it with more rigor, here is how it seems to work :
- before you enter a Perl script, the individual qglobals $XXX variables are loaded in the Perl interpreter for this zone server. Any variable defined in qglobals is set with its value from the DB, for this character (accounting for timestamps, NPC-specific variables etc)
- the $qglobals map is also initialized ANEW, at the same time (the ANEW is important here, the $qglobals starts from scratch for each script interpretation)
- there is a good chance that the Perl interpreter is reused as-is in the next script, to reduce CPU-load. The qglobals for the new PC/NPC are simply reloaded FOR THE VALUES DEFINED, but nothing is undefined as it is a complex problem to know what variables need to be undefined in the global store.

The real problem is "stale" variables from the previous PC. They are not undefined in the Perl interpreter before switching to the next PC/NPC. The $qglobals variable is not undefined either, but as it is overwritten each time with the full qglobals map (which is computed from an empty map for each script) it does not have any noticeable effect. This is why the $qglobals map is more reliable.

One test you could make to validate this assumption is : have two PCs of different levels (say 72 and 74) do the delevel quest. Their $max_level will be set to the appropriate value. If they do the turn-in they will both return to their proper level, because the variable is defined for them. Then have a level 70 character do the delevel-relevel. As its $max_level will not be set (you can see it in the DB), it should use the $max_level of the previous PC for this zone server.

Doing a #reloadquest reinitializes the Perl interpreter so the "stale" variables are removed (and the problem hidden).

I had a similar problem with temporary variables that were not erased unless I undefined them forcefully. Looks like using $qglobals will avoid this forceful deletion. I will try it when I am back to that point in my tools

Validating that (on another server than mine) would be a clear indication that $qglobals is a must from now on.
Reply With Quote
  #7  
Old 05-25-2008, 08:58 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

So, to make sure I understand this clearly, if I want to check for a certain global variable, I would use something like this:

Code:
if (defined($qglobals{max_level}) == 75)
?
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #8  
Old 05-25-2008, 10:51 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Or maybe it should be:

Code:
if (defined($qglobals{max_level} == 75))
I guess I will need to test them both out when I get home and see which one works. Hopefully one of them does.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #9  
Old 05-26-2008, 01:00 AM
Bulle
Hill Giant
 
Join Date: Jan 2008
Posts: 102
Default

No

You need just remember that $qglobals{max_level} is the replacement for $max_level.

So you could use :
Code:
if(defined($qglobals{max_level}))
to check that the variable is defined, in the same way you could have used if(defined($max_level))

Or you could use :
Code:
if($qglobals{max_level}) == 75)
to check if the variable is equal to 75 (after you have ensured it is defined !), in the same way you could have used if($max_level == 75)

If you want the safe solution in one "if" :
Code:
if(defined($qglobals{max_level}) && $qglobals{max_level} == 75)
With cascading "if"s :
Code:
if(!defined($qglobals{max_level}))
{ # Here you assume Max Level is 70 I guess
}
elsif($qglobals{max_level} == 71)
{ # Max Level is 71
}
elsif($qglobals{max_level} == 72)
{ # Max Level is 72
}
elsif($qglobals{max_level} == 73)
{ # Max Level is 73
}
elsif($qglobals{max_level} == 74)
{ # Max Level is 74
}
elsif($qglobals{max_level} == 75)
{ # Max Level is 75
}
else
{ # Damnit ! A super-hero !
}
Finally you can use a temporary variable (for a briefer notation), I just hope you won't get a warning in case the quest global is not defined, Perl's subtleties sometimes evade me :
Code:
$MaxLevel = $qglobals{max_level};
if(defined($MaxLevel) && $MaxLevel  == 75)
Notice how I propose a temporary variable different from max_level, to avoid any new weirdness

Note that to undefine a Perl variable I normally use this, instead of $XXX = undef :
Code:
undef($XXX);
I do not know whether both are equivalent. To delete a quest global from the DB the function to use is quest::delglobal as Gonner mentioned, which probably does NOT "undef" the associated variable. I have no idea whether the $qglobals map is updated at the same time, or only on next call to the script. This will have to be tested. it is the best way to know. In fact this should be tested for both delglobal and setglobal, and I hope they behave in a consistent way.
Reply With Quote
  #10  
Old 05-26-2008, 02:37 AM
Bulle
Hill Giant
 
Join Date: Jan 2008
Posts: 102
Default

I have made a few more tests with the following quest script. It is a bit long but it prints the variables at the start and end of the script :
Code:
my $LevelItemId = 1038; # Tattered Cloth Sandal
my $DefaultMaxLevel = 70;


sub EVENT_SAY
{ if(defined($maxxx_level))
  { print "maxxx_level($name) begin = $maxxx_level"; }
  else
  { print "maxxx_level($name) begin is not defined"; }
  
  if(defined($qglobals{maxxx_level}))
  { print "qglobals{maxxx_level}($name) begin = $qglobals{maxxx_level}"; }
  else
  { print "qglobals{maxxx_level}($name) begin is not defined"; }
  
  if(($text=~/65/i) && ($ulevel >= 70))
  { quest::say("Remember, DO NOT lose that trinket ! Welcome to level 65 !");
    quest::summonitem(1038);
    quest::level(65);
  }
  
  if($text=~/make me a newb/i)
  { quest::say("Arrr Arrr Arrr, my pleasure !");
    quest::level(1);
    quest::delglobal("maxxx_level"); undef($qglobals{maxxx_level});
  }
  if($text=~/make me level 73/i)
  { quest::say("OK, you're the boss after all *sigh*");
    quest::level(73);
    quest::setglobal("maxxx_level", 73, 5, "F"); $qglobals{maxxx_level} = 73;
  }
  if($text=~/make me level 75/i)
  { quest::say("OK, you're the boss after all *sigh*");
    quest::level(75);
    quest::setglobal("maxxx_level", 75, 5, "F"); $qglobals{maxxx_level} = 75;
  }

  if(defined($maxxx_level))
  { print "maxxx_level($name) end = $maxxx_level"; }
  else
  { print "maxxx_level($name) end is not defined"; }
  
  if(defined($qglobals{maxxx_level}))
  { print "qglobals{maxxx_level}($name) end = $qglobals{maxxx_level}"; }
  else
  { print "qglobals{maxxx_level}($name) end is not defined"; }
}


sub EVENT_ITEM
{ if(defined($maxxx_level))
  { print "maxxx_level($name) begin = $maxxx_level"; }
  else
  { print "maxxx_level($name) begin is not defined"; }
  
  if(defined($qglobals{maxxx_level}))
  { print "qglobals{maxxx_level}($name) begin = $qglobals{maxxx_level}"; }
  else
  { print "qglobals{maxxx_level}($name) begin is not defined"; }
  
  if(plugin::check_handin(\%itemcount, $LevelItemId => 1))
  { if(defined($qglobals{maxxx_level}))
    { quest::say("Welcome back to level $qglobals{maxxx_level}, $name");
      quest::level($qglobals{maxxx_level});
    }
    else
    { quest::say("Welcome back to level $DefaultMaxLevel, $name");
      quest::level($DefaultMaxLevel);
    }
  }
  else
  { plugin::return_items(\%itemcount);
    quest::say("I have no use for this item, $name.  Take it back.");
  } 

  if(defined($maxxx_level))
  { print "maxxx_level($name) end = $maxxx_level"; }
  else
  { print "maxxx_level($name) end is not defined"; }
  
  if(defined($qglobals{maxxx_level}))
  { print "qglobals{maxxx_level}($name) end = $qglobals{maxxx_level}"; }
  else
  { print "qglobals{maxxx_level}($name) end is not defined"; }
}
I have removed some level choices for simplicity.

Currently quest::...global do not update the $qglobals map to keep it in sync with DB changes done in the script so you have to update $qglobals explicitly.

As it is the script works fine : it updates the DB globals with quest::...global, and at the same time updates the $qglobals map for consistency, to keep them in sync.
If you code this way you can even re-read the $qglobals in the same sub, and it is consistent with what has been entered in the DB. It could be a nice "coding rule" for script writing. Best would be if the Emu server did that synchronization in quest::...global itself, I will have to look into that.
Reply With Quote
  #11  
Old 05-26-2008, 04:48 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

/bonks self

... Yeah, I see now. Sometimes the different ways people write things throws me off lol. I got it working perfectly so far. I think that should definitely do the trick. Thanks a ton, cause I was sick of having this issue so long lol.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
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 06:42 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