Go Back   EQEmulator Home > EQEmulator Forums > Archives > Archive::Development > Archive::Quests

Archive::Quests Archive area for Quests's posts that were moved here after an inactivity period of 90 days.

Reply
 
Thread Tools Display Modes
  #1  
Old 08-15-2004, 04:18 AM
Cisyouc
Demi-God
 
Join Date: Jun 2004
Location: Heaven.
Posts: 1,260
Default LDoN Recruiter v0.1 Beta (MMC)

Hello, all!
After noticing that many server's haven't really used the LDoN zones, I decided to take up this project to create an adventure recruiter using only (if I can), Perl Quests. After a few days of tinkering with it, making it as easy as I can to set up, I have created a system that is NOT PERFECT BY ANY MEANS!! Compared to the EQLive system it is very inefficient and buggy. Here is a discription of what it does.

One of the main problems with this system is that LDoNs usually have mobs designated for your level. This system cannot do that, so if you use this, it is suggested that each dungeon be suited for a certain level range.

Sample (I cant give out a definate chart as everyone has a different max level):

MMCA for levels 10-15
MMCB for levels 15-20 (or hard version of mmca)
MMCC for levels 25-30 (or hard version of mmcb)
MMCD for levels 35-40 (or hard version of mmcc)
MMCE for levels 45-50 (or hard version of mmcd)
MMCF for levels 50-55 (or hard version of mmce)
MMCG for levels 55-60 (or hard version of mmcf)
MMCH for levels 60-65 (or hard version of mmcg)
MMCI for levels 65-70 (or 65+ if thats your max)
MMCJ for levels 70-75 (or 65+ if thats your max)

BETA VERSION is only for Mistmoore Catacombs. Once I work some bugs out I will make a .zip version for each theme.

So this is how it works:
Quote:
You say, 'Hail, Mistmoore Adventure Recruiter.'

Mistmoore Adventure Recruiter says, 'Greetings $name! The Wayfarer's Brotherhood is looking for new recruits to head into the Lost Dungeons of Norrath. Are you a young [adventurer]?'

You say, 'I am an adventurer.'

The Lost Dungeons that currently have no explorer's inside are:
The [Forlorn Caverns]
The [Dreary Grotto]
The [Asylum of Invoked Stone]
The [Chambers of Eternal Affliction]
The [Sepulcher of the Damned]
The [Ritualistic Summoning Ground]
The [Cesspits of Putresence]
The [Aisles of Blood]
The [Halls of Sanguinary Rites]
The [Infernal Sanctuary]
You will recieve XX adventure points from an adventure.
(XX would be replaced with player level minus 5)

You say, 'Forlorn Caverns'
Your Dungeon has NOT yet began. You must speak with the dungeon master to start.

(Forlorn Caverns is removed from the 'adventurer' list and if someone were to say 'forlorn caverns' they get a message saying that dungeon is not available.)
(Player is sent into the Forlorn Caverns)

You say, 'Hail, Dungeon Master'
Dungeon Master says, 'Thank Mithaniel, You're here $name! When you're ready to begin killing I will [start] the timer for you. Remember to come back to me when you're done to [end] the adventure, otherwise you won't be able to request a new adventure.'

You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expirerence!!
[ERROR]
You did not start the timer at the Dungeon Master located at the zone in! You did NOT Recieve Bonus Expierence for this kill and this kill did NOT count toward your reward.

You say, 'Start'
Your dungeon has began.

You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expierence!!
You have killed 1/50 Required Monsters.
You gain expierence!!
Bonus expierence was awarded for this kill.

You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expierence!!
You have killed 2/50 Required Monsters.
You gain expierence!!
Bonus expierence was awarded for this kill.

(...more kills pass...)

You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expierence!!
You have killed 49/50 Required Monsters.
You gain expierence!!
Bonus expierence was awarded for this kill.

You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expierence!!
You have completed your adventure!
You have recieved XX points for your adventure!
Please return to the dungeon master to exit.

You say, 'Hail, Dungeon Master.'
Dungeon Master says, 'Thank you for completing this dungeon!'
(You are sent into Butcherblock at Recruiter.)
(Forlorn Caverns is back on the 'adventurer' list)
(All variables for kills and the like are back to 0)
Like EQLive, I have implemented an Hour and 30 Minute Timer, but it works a little different.

Lets say you are killing in a dungeon...
Quote:
You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expierence!!
You have killed 32/50 Required Monsters.
You gain expierence!!
Bonus expierence was awarded for this kill.

(Time Expires)

You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expierence!!
Your 1 Hour and 30 Minute Timer has expired. Please go to the dungeon master to end the dungeon. No Bonus Expierence was Awarded for this kill.

You slash A Scion Swirlything for 20000 points of damage!
You have slain A Scion Swirlything!
You gain expierence!!
Your 1 Hour and 30 Minute Timer has expired. Please go to the dungeon master to end the dungeon. No Bonus Expierence was Awarded for this kill.

You say, 'Hail, Dungeon Master'
Dungeon Master says, 'Hello Again, $name. You may [end] this dungeon if it need be now.'

You say, 'End'

Dungeon Master says, 'Thanks for the help!'
(Forlorn Caverns is put back on the list.)
(All variables are reset to 0.)
Now lets say someone in the group DID NOT /say end the adventure, it CAN mess up the adventure recruiter because they expect you to still be in there. However, once the timer runs out all but 2 variables are reset to 0, and 1 of them will automatically change 1:40:00 after the adventure was /say start'd. (and that is the variable that tells the recruiter if its empty. 0 for yes, 1 for no). The other one just tells the Dungeon Master what to say on hail. So when the next group comes, when they hail the Dungeon Master to start the adventure, they will automatically be ported back to BB as if they won the adventure (no points awarded). All they have to do is ask for Forlorn Caverns again, and they can continue playing.

========================
DEBUGGING
========================

Because the system has many flaws, I have implemented for GMs or whoever is setting up the quest wants, a DEBUG feature. What this basically does is reset's all the variables back to 0. There is a debug feature on both the Adventure Recruiter and Dungeon Master. Its DEFAULT MINIMUM STATUS to allow you to debug is 200, but you can change that on this line found in both quest pages:
Code:
if($text=~/debug/i)
  {
  if($status >= 200)
    {
Once debugged on both NPC's, the adventure system is all clear, meaning that all dungeons will be available on the recruiter, the timer in the dungeon has been stopped, and kills has been reset to 0 (as if it has been /say end'd fine).

========================
Installation
========================
To install this on your server you must HAVE the following.
  • quest_globals.sql sourced into your database.
  • Knowledge of targlobal(), setglobal(), delglobal();
  • Knowledge of how to compile an EQEMu Source (You WONT need to, but if you don't know how to compile you probably won't understand my guide.)
  • Knowledge of EQEMu itself.
  • Preferably, access to the following commands: #zone, #spawn, #npcspawn, or a ZoneViewer and Access to the Database.
  • Access to ./quests

Now, to begin, you will need to:
  • Spawn an Adventure Recruiter in Butcherblock. EQLive (and default for this quest) is "Xyzelauna_Tu`Valzir", a level 65 Dark Elf Warrior, texture 3 helm 2, located at ButcherBlock -2493, -1124, -5.3 heading 6.0.
  • Spawn a Dungeon Master at the zone-in of every dungeon. (mmca, mmcb, mmcc, mmcd, mmce, mmcf, mmcg, mmch, mmci, mmcj.) It is suggested you make this npc level 255 or something, hence, unkillable.
  • Spawn at LEAST 50 (unless you change the amount of needed mobs to win) mobs per dungeon. Use the EQEMu guidebook for ldon _chr models and numbers.

Each type of mob should be inserted so the npc type itself has the same npc_types id.

EVERY NPC TYPE ID that is in a dungeon (mmca, mmcb, mmcc, etc..) and is a MOB that you are supposed to kill MUST have this quest attached to it.

Along with the quest, EVERY NPC TYPE ID must have qglobal to "1". Whether its a mob being killed, the dungeon master or the Recruiter. it MUST have qglobal ON (which is "1").

The quest you have to put for the MOBS-TO-BE-KILLED in the dungeons is this:
Code:
###################################################################
#Cisyouc`s Zone Instancing System                                 
#Lost Dungeons of Norrath					  
#Created by CISYOUC of Prexus II				  
#For Development of Any Server on the EQEMulator.net Network.	  
#Please do not remove this header.				  
#								  
#NPCID               : 000000					  
#ZONE                : mmca - mmcj				  
#NPC USAGE           : Adventure Mob 			          
###################################################################
sub EVENT_DEATH
{
if($done == 0)
  {
  if($began == 1)
    {
    if($kills <= 49)
      {
      $remaining = ((50-$kills));
      quest::setglobal("kills",$kills + 1,"3","T013000");
      quest::me("You have killed $kills/50 Required Monsters.");
      $calcexp1 = (($ulevel*5));
      $bonusexp = (($calcexp1*1000));
      quest::exp($bonusexp);
      quest::me("Bonus Expierence was Awarded for this kill.");
      }
    if($kills == 50)
      {
      $calc2 = (($ulevel-5));
      quest::addldonpoints($calc2,3);
      quest::me("You have completed your Adventure!");
      quest::me("You have recieved $calc2 points for your adventure!");
      quest::me("Please return to the Dungeon Master to exit.");
      quest::setglobal("gotpoints","1","3","T010000");
      }
    if($kills >= 51)
      {
      quest::me("You have killed $kills/50 Required Monsters.");
      quest::me("You have already won this adventure; no bonus expierence was awarded and this kill did NOT count toward an adventure point reward.");
      }
    }
   if($began == 0)
     {
     quest::me("[ERROR]");
     quest::me("You did not start the timer at the Dungeon Master located at the zone in! You did NOT Recieve Bonus Expierence for this kill and this kill did NOT count toward your reward.");
     }
   }
   if($done == 1)
     {
     quest::me("[ERROR]");
     quest::me("Your 1 Hour and 30 Minute Timer has expired. Please go to the dungeon master to end the dungeon. No Bonus Expierence was Awarded for this kill.");
     }
   }
}
########################################################
#END
For the Adventure Recruiter:
Code:
###################################################################
#Cisyouc`s Zone Instancing System                                 
#Lost Dungeons of Norrath					  
#Created by CISYOUC of Prexus II				  
#For Development of Any Server on the EQEMulator.net Network.	  
#Please do not remove this header.				  
#								  
#NPCID               : 000000					  
#ZONE                : butcher					  
#NPC USAGE           : Adventure Recruiter			  
###################################################################
#
sub EVENT_SAY
{
if($adven == 0){
if($ulevel >= 10){
if($text=~/hail/i)
  {
  quest::say("Greetings $name! The Wayfarer's Brotherhood is looking for new recruits to head into the Lost Dungeons of Norrath. Are you a young [adventurer]?");
  }
if($text=~/adventurer/i)
  {
     quest::me("The Lost Dungeons that currently have no explorer's inside are:");
     
   if($mmca == 0)
     {
     quest::me("The [Forlorn Caverns]");
     }
   if($mmcb == 0)
     {
     quest::me("The [Dreary Grotto]");
     }
   if($mmcc == 0)
     {
     quest::me("The [Asylum of Invoked Stone]");
     }
   if($mmcd == 0)
     {
     quest::me("The [Chambers of Eternal Afflictions]");
     }
   if($mmce == 0)
     {
     quest::me("The [Sepulcher of the Damned]");
     }
   if($mmcf == 0)
     {
     quest::me("The [Ritualistic Summoning Ground]");
     }
   if($mmcg == 0)
     {
     quest::me("The [Cesspits of Putresence]");
     }
   if($mmch == 0)
     {
     quest::me("The [Aisles of Blood]");
     }
   if($mmci == 0)
     {
     quest::me("The [Halls of Sanguinary Rites]");
     }
   if(mmcj == 0)
     {
     quest::me("The [Infernal Sanctuary]");
     }
     $result = (($ulevel-5));
     quest::me("Your level allows you to get $result points from this adventure.");
     
  }
if($text=~/forlorn caverns/i)
  {
  if($mmca == 0)
    {
    quest::targlobal("mmca","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");
    quest::movegrp(233,-589,-383,8.05);
    }
  if($mmca == 1)
    {
    quest::me("''mmca'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/dreary grotto/i)
  {
  if($mmcb == 0)
    {
    quest::targlobal("mmcb","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(238,-525,-26,23.67);
    }
  if($mmcb == 1)
    {
    quest::me("''mmcb'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/Asylum of Invoked Stone/i)
  {
  if($mmcc == 0)
    {
    quest::targlobal("mmcc","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(243,1229,510,-3.12);
    }
  if($mmcc == 1)
    {
    quest::me("''mmcc'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/Chambers of Eternal Affliction/i)
  {
  if($mmcd == 0)
    {
    quest::targlobal("mmcd","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(248,-228,-589,1.08);
    }
  if($mmcd == 1)
    {
    quest::me("''mmcd'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/sepulcher of the damned/i)
  {
  if($mmce == 0)
    {
    quest::targlobal("mmce","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(253,-578,330,1.11);
    }
  if($mmce == 1)
    {
    quest::me("''mmce'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/ritualistic summoning ground/i)
  {
  if($mmcf == 0)
    {
    quest::targlobal("mmcf","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(258,-167,400,-12.13);
    }
  if($mmcf == 1)
    {
    quest::me("''mmcf'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }

if($text=~/cesspits of putrescence/i)
  {
  if($mmcg == 0)
    {
    quest::targlobal("mmcg","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(263,425,405,3.82);
    }
  if($mmcg == 1)
    {
    quest::me("''mmcg'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/aisles of blood/i)
  {
  if($mmch == 0)
    {
    quest::targlobal("mmch","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(268,-340,-331,20.35);
    }
  if($mmch == 1)
    {
    quest::me("''mmch'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/halls of sanguinary rites/i)
  {
  if($mmci == 0)
    {
    quest::targlobal("mmci","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(272,592,-283,3.78);
    }
  if($mmci == 1)
    {
    quest::me("''mmci'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
  }
if($text=~/infernal sanctuary/i)
  {
  if($mmcj == 0)
    {
    quest::targlobal("mmcj","1","T014500",68134,$charid,68);
    quest::setglobal("adven","1","5","T013000");
    quest::me("Your Dungeon has NOT yet began. You must speak with the dungeon master to start.");

    quest::movegrp(276,227,538.3.87);
    }
  if($mmcj == 1)
    {
    quest::me("''mmcj'' is currently in use at this time. After a dungeon is initiated, you must wait 90 minutes before it can become available again. If you feel this message is in error, please petition now.");
    }
   else
   {
   quest::me("That dungeon is not available at this time.");
   }
  }
if($text=~/debug/i)
  {
  if($status >= 200)
    {
    quest::delglobal(adven);
    quest::targlobal("mmca","0","C999999",68134,$charid,68);
    quest::targlobal("mmcb","0","C999999",68134,$charid,68);
    quest::targlobal("mmcc","0","C999999",68134,$charid,68);
    quest::targlobal("mmcd","0","C999999",68134,$charid,68);
    quest::targlobal("mmcc","0","C999999",68134,$charid,68);
    quest::targlobal("mmcf","0","C999999",68134,$charid,68);
    quest::targlobal("mmcg","0","C999999",68134,$charid,68);
    quest::targlobal("mmch","0","C999999",68134,$charid,68);
    quest::targlobal("mmci","0","C999999",68134,$charid,68);
    quest::targlobal("mmcj","0","C999999",68134,$charid,68);

    quest::me("Debugged.");
    }
  else
    {
    quest::me("You do not have the permissions needed to debug the adventure recruiter.");
    } 
  }
 }
else
{
quest::say("You must prove your dedication before I can discuss such matters with you.");
}
}
}
if($adven == 1)
  {
  if($text=~/hail/i)
    {
    quest::say("You currently have an active adventure and you must wait for expiration before you can request again.");
    }
  }


sub EVENT_TIMER
{
quest::setglobal("adven","0","0","C999999");
}
########################################################
#END


IMPORTANT: For each dungeon master (in each dungeon) you must REPLACE 'mmca' everywhere in the code for the zone its in. So lets say I was putting this in mmcb, i'd need to open up this in notepad, go to Edit>Replace, and REPLACE ALL mmca to mmcb. This is CRUCIAL. Because each Dungeon Master is in a different zone, he CAN have the same npc_types id however.

Inside the code you will see a targlobal line that looks like either:
Code:
quest::targlobal("mmca","0","C999999",68134,$charid,68);
ALONG with changing the "mmca", you need to change the 68134 to the NPC_TYPES ID of your Recruiter. Xyzelauna Tu`Valzir`s default npc_id in peq i believe is that, because that is what it was on my server, but it may not be. So you MUST change this ID to what you want it to be.

You will need to change the 68134 in BOTH the Dungeon Master and the Adventure Recruiter Codes.

Dungeon Master Code:
Code:
###################################################################
#Cisyouc`s Zone Instancing System                                 
#Lost Dungeons of Norrath					  
#Created by CISYOUC of Prexus II				  
#For Development of Any Server on the EQEMulator.net Network.	  
#Please do not remove this header!!!!!!				  
#								  
#NPCID               : 000000					  
#ZONE                : mmca           			          
#NPC USAGE           : Dungeon Master 			          
###################################################################
sub EVENT_SAY
{
if($text=~/hail/i)
  {
  if($done == 1)
    {
    quest::say("Thank you all for completing this dungeon!");
    quest::stoptimer(1);
    quest::setglobal("kills","0","3","C999999");
    quest::setglobal("adven","0","5","C999999");
    quest::setglobal("began","0","3","C999999");
    quest::setglobal("done","0","3","C999999");
    quest::setglobal("gotpoints","0","3","C999999");
    quest::targlobal("mmca","0","C999999",68134,$charid,68);
    quest::movegrp(68,-2490,-1102,1.16);
    }
  if($done == 0)
    {
    if($began == 0)
      {
      quest::say("Thank Mithaniel, You're here $name! When you're ready to begin killing I will [start] the timer for you. Remember to come back to me when you're done to [end] the adventure, otherwise you won't be able to request a new adventure.");
      }
    if($began == 1)
      {
      quest::say("Hello Again, $name. You may [end] this dungeon if it need be now.");
      }
    }
  }
if($text=~/end/i)
  {
  quest::say("Thanks for the help!");
  quest::stoptimer(1);
  quest::setglobal("kills","0","3","C999999");
  quest::setglobal("adven","0","5","C999999");
  quest::setglobal("began","0","3","C999999");
  quest::setglobal("done","0","3","T013000");
  quest::setglobal("gotpoints","0","3","C999999");
  quest::targlobal("mmca","0","C999999",68134,$charid,68);
  quest::movegrp(68,-2490,-1102,1.16);
  }
if($text=~/start/i)
  {
  quest::me("Your dungeon has began.");
  quest::setglobal("kills","1","3","T013000");
  quest::setglobal("began","1","3","T013000");
  quest::settimer(1,5400);
  }
if($text=~/debug/i)
  {
  if($status >= 200)
    {
    quest::stoptimer(1);
    quest::setglobal("kills","0","3","C999999");
    quest::setglobal("adven","0","5","C999999");
    quest::setglobal("began","0","3","C999999");
    quest::setglobal("done","0","3","T013000");
    quest::setglobal("gotpoints","0","3","C999999");
    quest::targlobal("mmca","0","C999999",68134,$charid,68);
    quest::me("Debugged.");
    }
  else
    {
    quest::me("You do not have the permissions to debug this NPC.");
    }
  }
}
sub EVENT_TIMER
{
 quest::setglobal("adven","0","5","C999999");
 quest::targlobal("mmca","0","C999999",68134,$charid,68);
 quest::setglobal("done","1","3","T013000");
 quest::setglobal("kills","0","3","C999999");
 quest::setglobal("gotpoints","0","3","C999999");
 quest::targlobal("mmca","0","C999999",68134,$charid,68);
 quest::movegrp(68,-2490,-1102,1.16);
}
########################################
#END
I know this code is pretty buggy however it IS a start. At least some of the dungeons will be working if set up correctly. If you cannot get this set up theres not much I can do, my instructions are as clear as I can get them, lol. However if you think you followed the guide right and somethings still not right let me know, however if its a database issue (like ' how do i spawn mobs?' or 'every time i spawn a mob it has a different id!!') I won't be able to help. If theres a misspelling anywhere in the quest let me know, but Ive tested it on my server and it all checked out OK (as far as it could.)

Any Comments/Suggestions are welcome.
__________________
namespace retval { template <class T> class ReturnValueGen { private: T x; public: ReturnValueGen() { x = 0; }; T& Generator() { return x; }; }; } int main() { retval::ReturnValueGen<int> retvalue; return retvalue.Generator(); }
C++ is wonderful.
Reply With Quote
  #2  
Old 08-15-2004, 05:38 AM
sotonin
Demi-God
 
Join Date: May 2004
Posts: 1,177
Default

very cool. )
Reply With Quote
  #3  
Old 08-15-2004, 08:08 AM
killspree
Dragon
 
Join Date: Jun 2002
Posts: 776
Default

I had code for an adventure system as well if you want that when I recode it. It was set up so that a number of level ranges could spawn within a zone based on the flag level of the person entering the zone. Will go well with instancing when I get the time to work on that eventually.

I'll post it when I get back to recoding stuff...still working on a few other projects atm.
__________________
Xeldan
Lead Content Designer
Shards of Dalaya
Reply With Quote
  #4  
Old 08-15-2004, 08:54 AM
Cisyouc
Demi-God
 
Join Date: Jun 2004
Location: Heaven.
Posts: 1,260
Default

Quote:
Originally Posted by killspree
I had code for an adventure system as well if you want that when I recode it. It was set up so that a number of level ranges could spawn within a zone based on the flag level of the person entering the zone. Will go well with instancing when I get the time to work on that eventually.

I'll post it when I get back to recoding stuff...still working on a few other projects atm.
It would be easy enough making the zoned spawn mobs appropriate to a certain level except to have 50+ spawn commands would cause the zone to crash.
__________________
namespace retval { template <class T> class ReturnValueGen { private: T x; public: ReturnValueGen() { x = 0; }; T& Generator() { return x; }; }; } int main() { retval::ReturnValueGen<int> retvalue; return retvalue.Generator(); }
C++ is wonderful.
Reply With Quote
  #5  
Old 08-15-2004, 08:58 AM
killspree
Dragon
 
Join Date: Jun 2002
Posts: 776
Default

Right, so this is a simple addition to the loadspawn2 function in zone.cpp. I got bored with what I was doing, so I'm working on it now. It'll load up a certain set of spawns based on the qglobal of the zones shortname. It'll require an additional field in the spawn2 table, but other than that everything else is code, and spawn2 will continue to work like normal after adding this.

You'll have to manually add new levels of spawns per level range you want. My question is this: How do you want it set up? Do you want it to check against the "value" field in quest_globals for the level range to spawn?
__________________
Xeldan
Lead Content Designer
Shards of Dalaya
Reply With Quote
  #6  
Old 08-15-2004, 09:21 AM
Cisyouc
Demi-God
 
Join Date: Jun 2004
Location: Heaven.
Posts: 1,260
Default

Quote:
Originally Posted by killspree
Right, so this is a simple addition to the loadspawn2 function in zone.cpp. I got bored with what I was doing, so I'm working on it now. It'll load up a certain set of spawns based on the qglobal of the zones shortname. It'll require an additional field in the spawn2 table, but other than that everything else is code, and spawn2 will continue to work like normal after adding this.

You'll have to manually add new levels of spawns per level range you want. My question is this: How do you want it set up? Do you want it to check against the "value" field in quest_globals for the level range to spawn?
I'm not sure. I could make a new variable if it need be:

Under each dungeon long-name at the recruiter, add
Code:
$mmca-leveladj = (($ulevel-2));
quest::setglobal("mmca-level",$mmca-leveladj","7","T013000");
.

And your code would check the value of `mmca-level` in `quest_globals`?

OR

Would there be a way to add 2 new columns in npc_types, lets say.. Levcheck, varicheck.

If `levcheck` = `1`, make new level of npc the value of a value in quest_globals (and you would identify the name of the global that has the level value in the 2nd column, varicheck)

OR

Am I just making this way too complicated than it should?
__________________
namespace retval { template <class T> class ReturnValueGen { private: T x; public: ReturnValueGen() { x = 0; }; T& Generator() { return x; }; }; } int main() { retval::ReturnValueGen<int> retvalue; return retvalue.Generator(); }
C++ is wonderful.
Reply With Quote
  #7  
Old 08-15-2004, 09:35 AM
killspree
Dragon
 
Join Date: Jun 2002
Posts: 776
Default

Ok, it's been so long since I wrote the code that I'm mistaken on where it goes...it's not in loadspawn2. Anyways, the idea is that it will simply check the same qglobal that the quest script checks to see whether or not the zone is in use. It'll require the quest script to be written a little different than you have it(> 0 instead of == 1), but other than that...it doesn't require any extra scripting on the quest writers part over what you already have.
__________________
Xeldan
Lead Content Designer
Shards of Dalaya
Reply With Quote
  #8  
Old 08-15-2004, 10:25 AM
killspree
Dragon
 
Join Date: Jun 2002
Posts: 776
Default

Actually, nevermind that. I'll just add a new function to update the adventure level in the zone table. It's temporary while I work on instancing - eventually it'll pull it from a new table that deals with each specific instance. Testing it now and the spawns are only appearing if their advlevel is the same as the advlevel for that specific zone in the zone table. Will work on the function to update it now.
__________________
Xeldan
Lead Content Designer
Shards of Dalaya
Reply With Quote
  #9  
Old 08-15-2004, 10:52 AM
killspree
Dragon
 
Join Date: Jun 2002
Posts: 776
Default

Hmm...after some testing, the variables in your script don't work properly. I get no response after the initial run through the quest. Once the qglobals are set he doesn't respond at all - including the message that the person already has an adventure.
__________________
Xeldan
Lead Content Designer
Shards of Dalaya
Reply With Quote
  #10  
Old 08-15-2004, 11:24 AM
killspree
Dragon
 
Join Date: Jun 2002
Posts: 776
Default

Ok, here are the changes needed to get this working. Firstly the code changes.

In zone.cpp ~line 1037 you'll find bool Database::PopulateZoneSpawnList(const char* zone_name, LinkedList&lt;Spawn2*> &amp;spawn2_list, int32 repopdelay) - replace that entire function with:
Code:
bool Database::PopulateZoneSpawnList(const char* zone_name, LinkedList&lt;Spawn2*> &amp;spawn2_list, int32 repopdelay) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char* query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int8 advlevel=CheckAdvLevel(zone->GetShortName());

       //Killspree: Added advlevel to query - spawns are loaded from spawn2 where advlevel is = to the value returned by CheckAdvLevel() above.
	   MakeAnyLenString(&amp;query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, timeleft FROM spawn2 WHERE zone='%s' AND advlevel=%i", zone_name, advlevel);
	
	   if (RunQuery(query, strlen(query), errbuf, &amp;result))
	   {
		   safe_delete_array(query);
		   while((row = mysql_fetch_row(result)))
		   {
			      Spawn2* newSpawn = 0;
						//if(GetInverseXY()==1) {
						//	newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[3]), atof(row[2]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]));
						//}
						//else {
			      newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), atoi(row[9]), atoi(row[8]));
						//}
			            //newSpawn->Repop(repopdelay);
			      spawn2_list.Insert( newSpawn );
		   }
		mysql_free_result(result);
	   }
	else
	{
		cerr &lt;&lt; "Error in PopulateZoneLists query '" &lt;&lt; query &lt;&lt; "' " &lt;&lt; errbuf &lt;&lt; endl;
		safe_delete_array(query);
		return false;
	}
	
	return true;
}
Above that we'll add the new function, CheckAdvLevel():
Code:
int8 CheckAdvLevel(const char* shortname){
    char errbuf[MYSQL_ERRMSG_SIZE]; 
    char *query = 0; 
    MYSQL_RES *result; 
    MYSQL_ROW row; 
   if (database.RunQuery(query, MakeAnyLenString(&amp;query, "SELECT advlevel FROM zone WHERE short_name='%s'",shortname), errbuf, &amp;result)) { 
      safe_delete_array(query); 
      if (mysql_num_rows(result) == 1) 
      { 
         row = mysql_fetch_row(result); 
         int8 advlevel = atoi(row[0]); 
         mysql_free_result(result); 
         return advlevel; 
      } 
      else 
      { 
         mysql_free_result(result); 
         return 0; 
      } 
      mysql_free_result(result); 
   } 
   else 
   { 
      cerr &lt;&lt; "Error in CheckAdvLevel query '" &lt;&lt; query &lt;&lt; "' " &lt;&lt; errbuf &lt;&lt; endl; 
      safe_delete_array(query); 
      return false; 
   } 
    
   return 0;
}
That's all you need to do to get zones spawning based on the advlevel field in the zones table code-wise. Now on to the function to update the advlevel. This is a perl function.

parser.cpp ~line 1133 add:
Code:
         else if (!strcmp(strlwr(command),"setadvlevel")){ 
               char errbuf[MYSQL_ERRMSG_SIZE]; 
               char *query = 0; 
               int8 advlevel = atoi(arglist[0]); 
               int16 zoneid = atoi(arglist[1]); 
    
               if (!database.RunQuery(query, MakeAnyLenString(&amp;query, "UPDATE zone SET advlevel = %i where zoneidnumber = %i", advlevel, zoneid), errbuf)) { 
                   cerr &lt;&lt; "Error in SetAdvLevel query '" &lt;&lt; query &lt;&lt; "' " &lt;&lt; errbuf &lt;&lt; endl; 
                   safe_delete_array(query); 
            } 
               safe_delete_array(query); 
         }
embparser.cpp ~line 504 add:
Code:
"sub setadvlevel{push(@cmd_queue,{func=>'setadvlevel',args=>join(',',@_)});}"
Now for database changes...you'll need to run the following in mysql.

For the zone table:
Code:
ALTER TABLE `zone` ADD `advlevel` INT(4) DEFAULT "0" NOT NULL AFTER `weather`
And for the spawn2 table:
Code:
ALTER TABLE `spawn2` ADD `advlevel` INT(4) DEFAULT "0" NOT NULL AFTER `timeleft`
How to use setadvlevel() quest function:
quest::setadvlevel("advlevelvalue","zoneid");

advlevelvalue is the value you want the advlevel to be set to in the zone table.
zoneid is the zoneid of the zone that the advlevel will be altered for in the zone table.

You'll want to have corresponding advlevel values in spawn2 for each value there will be in zone. So lets say we want to spawn NPCs for a level 6 to 10 range, level 11 to 15 range, level 16 to 20 range, and level 21 to 25 range. You'll want to set up exact copies of the spawns in spawn2, each with a different advlevel value and their appropriate spawngroupID.

Example:
a_rat(level 6) spawns at 0,0,0 in west freeport. It'll have the advlevel value of 1.
a_rat(level 13) spawns at 0,0,0 in west freeport. It'll have the advlevel value of 2.
a_rat(level 17) spawns at 0,0,0 in west freeport. It'll have the advlevel value of 3.
a_rat(level 22) spawns at 0,0,0 in west freeport. It'll have the advlevel value of 4.

Now here is the trick - only one of those four will spawn, based on the advlevel value set in the zone table. the advlevel values MUST match for that specific npc to spawn.

Once I work on instancing, I'll post the updated code. Nothing should change much, just where the db query looks for the advlevel.
__________________
Xeldan
Lead Content Designer
Shards of Dalaya
Reply With Quote
  #11  
Old 08-15-2004, 11:38 AM
killspree
Dragon
 
Join Date: Jun 2002
Posts: 776
Default

Something else I'll mention is that this code allows for dynamic content, that can change on the fly, by simply repopping the zone. Lets say you want to set up a zone where there's a human settlement at the beginning, but if players explore into the nearby dungeon and kill an npc, it enrages the dungeons inhabitants and now they pour out into the adjacent zone and kill the human settlers. In the place of the settlers you can spawn the enraged dungeon NPCs...or just remove them and spawn new NPCs elsewhere in the zone.

It'll take additional perl scripting to initiate the event where the settlers are killed, but it's definitely possible to do.
__________________
Xeldan
Lead Content Designer
Shards of Dalaya
Reply With Quote
  #12  
Old 08-15-2004, 12:48 PM
sotonin
Demi-God
 
Join Date: May 2004
Posts: 1,177
Default

holy shit killspree. this sounds awesome )
Reply With Quote
  #13  
Old 08-15-2004, 02:39 PM
Cisyouc
Demi-God
 
Join Date: Jun 2004
Location: Heaven.
Posts: 1,260
Default

I'm sorry I didn't understand his code at all heehee.

Bah.
__________________
namespace retval { template <class T> class ReturnValueGen { private: T x; public: ReturnValueGen() { x = 0; }; T& Generator() { return x; }; }; } int main() { retval::ReturnValueGen<int> retvalue; return retvalue.Generator(); }
C++ is wonderful.
Reply With Quote
  #14  
Old 08-15-2004, 10:17 PM
cofruben
Old-EQEmu Developer
 
Join Date: Oct 2002
Location: Spain
Posts: 323
Default

nice work Cisyouc.
Reply With Quote
  #15  
Old 08-16-2004, 03:41 AM
Cisyouc
Demi-God
 
Join Date: Jun 2004
Location: Heaven.
Posts: 1,260
Default

Quote:
Originally Posted by killspree
Hmm...after some testing, the variables in your script don't work properly. I get no response after the initial run through the quest. Once the qglobals are set he doesn't respond at all - including the message that the person already has an adventure.
Hmm. I'll look at it, it's worked fine on two of my computers so far.

Also, make sure that all dungeons + butcherblock is NON-STATIC. Because the zone has to reboot for a few reasons.

-edit- Also, do you have a zone.exe output that has any errors or anything?
__________________
namespace retval { template <class T> class ReturnValueGen { private: T x; public: ReturnValueGen() { x = 0; }; T& Generator() { return x; }; }; } int main() { retval::ReturnValueGen<int> retvalue; return retvalue.Generator(); }
C++ is wonderful.
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 04:22 AM.


 

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