View Full Version : Porters
markusdabrave
04-03-2015, 03:42 PM
If I wanted to create a NPCs at the various Wizard Spires and Druid Rings that would teleport you to other spires/rings, what's the best way to go about it? I was thinking at first about a buff bot casting the teleport spell on you, but then I realized those are in-group spells so that probably wouldn't work. Plus I don't want the teleporter disappearing (though that would be kind of funny.. .which wizard spire/druid ring is the porter at :)). At any rate, I'm thinking more in terms of a translocator-type scenario. Or maybe something akin to the gnome in the guild hall that sends you off based on an item he gives you. From a design standpoint, what's the simplest way of doing this? Or is it even possible.
dagulus2
04-03-2015, 03:53 PM
You might want to take a look at the Wayfairer Magus scripts to see if they could be adapted to what you want.
markusdabrave
04-03-2015, 07:23 PM
Will do, thanks
Edit: Ok, I know this has got to be here. I was looking at buffbot spells and got my porters to work. The only problem is everything is instacast. I've done some searching for pause and wait in the scripts but can't seem to find anything of relevance to what I'm doing. Here's what I've got so far:
sub EVENT_SAY {
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? [Surefall] Glade?");
}
if ($text=~/Surefall/i) {
quest::say("Camo for safety...");
quest::selfcast(34);
quest::say("Off to Surefall Glade!");
quest::selfcast(2021);
}
}
I tried $npc->CastSpell(2021,$userid); but that only resulted in my NPC teleporting away (which was quite humorous... and may actually be something I implement later.. but I digress). My assumption here is that 2021 (Ring of Surefall) is a self-only spell, and 2020 (Circle of Surefall) is a group spell that the druid has to be a member of, which is why they're not working. Self-cast works but it's a little hoaky seeing a warrior cast a spell to teleport. So I guess there are a couple of questions:
1. Can I suppress the player character from doing the cast animation on a SelfCast?
2. What's the keyword for inserting a pause/wait between spells being cast? I saw pause(timer) but that didn't work so I suspect it only has to do with movement.
3. Is it even possible for an NPC to cast a group spell on a non-group member (similar to target group buff only this would really be target group circle :))
Asylum
04-12-2015, 01:32 PM
Avoid using "spells" altogether and simply use the following to move the player that triggers the event:
quest::movepc(zone_id, x, y, z, heading);
If you want a delay, set it to trigger a timer for x seconds, then under EVENT_TIMER paste the above (also may want to stop the timer...).
If you are transporting into an instance:
quest::MovePCInstance(zone_id, instance_id, x, y, z);
If you have a flare for the dramatic, have the npc cast a spell during the delay to make it appear that's the graphic he or she is casting.
See the second post in this thread http://www.eqemulator.org/forums/showthread.php?t=38773 for using proximity say to create and port player(s)/group to an instance. It can be used with quest::movepc(zone_id, x, y, z, heading); as well for static zones or to a different area of the same zone/instance. Be sure you activate the proximitysay command in EVENT_SPAWN or it will not use it.
markusdabrave
04-15-2015, 04:54 PM
Thanks for the advice, I'll give the movepc thing a try. You're exactly right on what my goal is. I'd like to make the porter cast 2-3 seconds of spell effects, then the player get teleported out. The problem I've run into is that everything happens sequentially. Timer -> Spell Effect -> Port rather than Timer & Spell Effect -> Port.
Right now this is what my code is. Functionally, it works fine. I'd like like it feel a little less botty and more pc-ish :)
Also, if there's a way to make this script not use so many if statements, I'm all ears. I'm new to perl but not programming so I suspect there has to be a way to combine those if statements into fewer lines of code.
sub EVENT_SAY {
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? [Butcherblock] Mountains, The [Feerrott], North [Karana], [Lavastorm] Mountains, [Misty] Thicket, [South Ro], [Steamfont] Mountains, West [Commonlands] or [Toxxulia] Forest?");
}
# if ($text=~/Surefall/i) {
# quest::selfcast(34);
# quest::say("Off to Surefall Glade!");
# quest::selfcast(2021);
# }
if ($text=~/Commonlands/i) {
quest::say("Off to West Commonlands!");
quest::selfcast(34);
quest::selfcast(531);
}
if ($text=~/Butcherblock/i) {
quest::say("Off to Butcherblock Mountains!");
quest::selfcast(34);
quest::selfcast(532);
}
if ($text=~/Feerrott/i) {
quest::say("Off to The Feerrott!");
quest::selfcast(34);
quest::selfcast(536);
}
if ($text=~/Karana/i) {
quest::say("Off to North Karana!");
quest::selfcast(34);
quest::selfcast(530);
}
if ($text=~/Lavastorm/i) {
quest::say("Off to Lavastorm Mountains!");
quest::selfcast(34);
quest::selfcast(534);
}
if ($text=~/Misty/i) {
quest::say("Off to Misty Thicket!");
quest::selfcast(34);
quest::selfcast(538);
}
if ($text=~/South Ro/i) {
quest::say("Off to South Ro!");
quest::selfcast(34);
quest::selfcast(535);
}
if ($text=~/Steamfont/i) {
quest::say("Off to Steafont Mountains!");
quest::selfcast(34);
quest::selfcast(537);
}
if ($text=~/Toxxulia/i) {
quest::say("Off you Toxxulia Forest!");
quest::selfcast(34);
quest::selfcast(533);
}
}
ghanja
04-15-2015, 05:08 PM
There is, but keeping with basics. It's better to use elsif's in place of all the other if's you have after the initial if.
sub EVENT_SAY {
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? [Butcherblock] Mountains, The [Feerrott], North [Karana], [Lavastorm] Mountains, [Misty] Thicket, [South Ro], [Steamfont] Mountains, West [Commonlands] or [Toxxulia] Forest?");
}
# elsif ($text=~/Surefall/i) {
# quest::selfcast(34);
# quest::say("Off to Surefall Glade!");
# quest::selfcast(2021);
# }
elsif ($text=~/Commonlands/i) {
quest::say("Off to West Commonlands!");
quest::selfcast(34);
quest::selfcast(531);
}
elsif ($text=~/Butcherblock/i) {
quest::say("Off to Butcherblock Mountains!");
quest::selfcast(34);
quest::selfcast(532);
}
elsif ($text=~/Feerrott/i) {
quest::say("Off to The Feerrott!");
quest::selfcast(34);
quest::selfcast(536);
}
elsif ($text=~/Karana/i) {
quest::say("Off to North Karana!");
quest::selfcast(34);
quest::selfcast(530);
}
elsif ($text=~/Lavastorm/i) {
quest::say("Off to Lavastorm Mountains!");
quest::selfcast(34);
quest::selfcast(534);
}
elsif ($text=~/Misty/i) {
quest::say("Off to Misty Thicket!");
quest::selfcast(34);
quest::selfcast(538);
}
elsif ($text=~/South Ro/i) {
quest::say("Off to South Ro!");
quest::selfcast(34);
quest::selfcast(535);
}
elsif ($text=~/Steamfont/i) {
quest::say("Off to Steafont Mountains!");
quest::selfcast(34);
quest::selfcast(537);
}
elsif ($text=~/Toxxulia/i) {
quest::say("Off you Toxxulia Forest!");
quest::selfcast(34);
quest::selfcast(533);
}
}
I've never used it on a port spell, but, if you're wanting effects and such, then perhaps:
$npc->SpellFinished(####, $client)
Or a timer with animation and aura that will do a movepc after a few seconds.
markusdabrave
04-15-2015, 06:20 PM
I made the recommended if->elsif changes. As a test, I added the SpellFinished function to the commonlands port. It's still insta-casting when I say Commonlands though. Code I'm using is below. I'm wondering if this is going to work since the NPC isn't casting the port spell, the player is self-casting it.
elsif ($text=~/Commonlands/i) {
quest::say("Off to West Commonlands!");
quest::selfcast(34);
$npc->SpellFinished(531, $client)
quest::selfcast(531);
}
ghanja
04-15-2015, 07:09 PM
$npc->SpellEffect(<effect>, <duration>);
Then a quest::movepc -- I like the control of it, and this assumes you may wish to send them somewhere other than the safe point.
markusdabrave
04-15-2015, 11:44 PM
Ok so the spell effect is working and the move command works great. I definitely like this better. However, timers still aren't cooperating. I'm so close I can taste it:
sub EVENT_SPAWN {
quest::settimer("portercast",10);
}
sub EVENT_TIMER {
if($timer eq "portercast") {
quest::say("Casting...");
quest::stoptimer("portercast");
quest::say("Moved");
}
}
sub EVENT_SAY {
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? [Butcherblock] Mountains, The [Feerrott], North [Karana], [Lavastorm] Mountains, [Misty] Thicket, [South Ro], [Steamfont] Mountains, West [Commonlands] or [Toxxulia] Forest?");
}
elsif ($text=~/Commonlands/i) {
quest::say("Off to West Commonlands!");
quest::settimer("portercast",10);
}
# quest::movepc(21, 1427, 479, -51, 0);
}
I think maybe this is an order thing. What happens is:
1. I /say commonlands
2. NPC says "Off to West Commonlands!"
3. NPC starts spell effect
4. 10 seconds later NPC says "Casting..." immediately followed by "Moved".
Seems like I'm getting hung up in the EVENT_TIMERS sub. The "Casting..." and "Moved" are something I just added in for testing instead of loading constantly. "Moved" is where my move line would be. So if I move it down past where the portercast timer is called in EVENT_SAY, it triggers simultaneously as the timer and I end up with "Moved" before "Casting..."
I could put the move command in the EVENT_TIMERS sub, but then I would have to mess with multiple timers, which seems like it would be defeating the purpose of using the timer. When you call a timer like that, where does the actual timer pause take place? Within EVENT_TIMERS would seem to be the obvious answer. Is there not a way to make the EVENT_SAY steps pause until the timer call is complete?
Edit:
I tried adding the move command to the EVENT_TIMERS sub but it doesn't function at all there.
ghanja
04-16-2015, 12:52 PM
quest::pause(xxx);
Think of timers as being independent/isolated, any code after a quest::settimer continues to run immediately. Timers can give the illusion of pause depending on what they do. When I mentioned timers, that was going a different route, not combining SpellEffect/SpellFinished and timers, sorry, I wasn't clear.
markusdabrave
04-16-2015, 05:01 PM
I'll give that a try tonight. If it's that simple, I'm going to feel really dumb :)
markusdabrave
04-16-2015, 09:29 PM
Negatory on the wait command. Doing some further research, that appears to be intended for pauses in waypoints. Man I got nothing now. Here's what the current code looks like. I've simplified it to its basics to troubleshoot:
sub EVENT_SAY {
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? [Butcherblock] Mountains, The [Feerrott], North [Karana], [Lavastorm] Mountains, [Misty] Thicket, [South Ro], [Steamfont] Mountains, West [Commonlands] or [Toxxulia] Forest?");
}
elsif ($text=~/Commonlands/i) {
quest::say("Off to West Commonlands!");
$client->SpellEffect(43,10);
quest::settimer("castdelay",10);
# quest::movepc(21, 1427, 479, -51, 0);
}
}
sub EVENT_TIMER {
if($timer eq "castdelay") {
#quest::stoptimer("castdelay");
quest::say("Off you go!");
quest::stoptimer("castdelay");
}
}
I've moved the quest::movepc command into the EVENT_TIMER if statement, but it doesn't seem to function there. If I leave it as seen above, it moves the player at the same time everything else happens. When I tried adding the quest::wait, I tried in both EVENT_TIMER and the EVENT_SAY subs but nothing.
ghanja
04-16-2015, 10:17 PM
Yeah pause is for waypoints and yet I still cite them as a pause. Sorry, cannot get that through this thick head for some reason (maybe if I used scripted travel it would stick).
Instead, I should have said:
sleep(x);
And I believe I'll step away until all the commotion has ceased so I can stop talking out of my arse.
ghanja
04-16-2015, 10:40 PM
Scratch that too. This is the NPC's script. Hmm.
markusdabrave
04-16-2015, 10:50 PM
LOL I know, I ran into that as well. However - success at last!! Apparently, there's not a built in delay so you have to write your own. I stumbled across this (http://www.eqemulator.org/forums/showthread.php?t=24282) thread and it's working like a champ.
sub EVENT_SAY{
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? [Butcherblock] Mountains, The [Feerrott], North [Karana], [Lavastorm] Mountains, [Misty] Thicket, [South Ro], [Steamfont] Mountains, West [Commonlands] or [Toxxulia] Forest?");
}
elsif ($text=~/Commonlands/i) {
quest::say("Off to West Commonlands!");
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(21, 1427, 479, -51, 0);
}
}
sub castdelay{
$delayOver = (time + @_[0]);
while (time < $delayOver){}
1;
}
Order of events is now:
1. /say commonlands to NPC
2. Spell Effect appears on player
3. Player self-invises
4. 5 seconds later player is moved to WC druid ring
Whew. Thanks for the help. I at least learned a lot :)
markusdabrave
04-17-2015, 12:19 AM
Ok, working, quasi-finished product:
sub castdelay{
$delayOver = (time + @_[0]);
while (time < $delayOver){}
1;
}
sub EVENT_SPAWN {
quest::settimer("portershout",90);
}
sub EVENT_TIMER {
if($timer eq "portershout") {
quest::shout("Porting to all druid locations! Hail me near tunnel to Qeynos Hills!");
$random_number = int(rand(100))+30; ## Randomizes porter shout after initial 90 second delay but no less than 30 seconds between shouts
quest::settimer("portershout", $random_number);
}
}
sub EVENT_SAY{
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? [Surefall] Glade, [Butcherblock] Mountains, The [Feerrott], North [Karana], [Lavastorm] Mountains, [Misty] Thicket, [South Ro], [Steamfont] Mountains, West [Commonlands] or [Toxxulia] Forest?");
}
elsif ($text=~/Commonlands/i) {
quest::say("Off to West Commonlands!");
$npc->DoAnim(43); #Cast animation
$client->SpellEffect(43,10); #Cast spell effect
castdelay(5); #invoke delay subroutine
quest::selfcast(34); #selfcast superior camo
quest::movepc(21, 1427, 479, -51, 0); #move PC to (zoneid, x, y, z, heading)
}
elsif ($text=~/Surefall/i) {
quest::say("Off to Surefall Glade!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(3, -391, -209, 4.75, 0);
}
elsif ($text=~/butcherblock/i) {
quest::say("Off to Butcherblock Mountains!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(68, 1984, -2135, 0);
}
elsif ($text=~/feerrott/i) {
quest::say("Off to The Feerrott!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(47, -1885, 367, 13.57, 0);
}
elsif ($text=~/karana/i) {
quest::say("Off to North Karana!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(13, -1494, -2706, -7.5, 0);
}
elsif ($text=~/lavastorm/i) {
quest::say("Off to Lavastorm Mountains!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(27, 460, 460, -84.88, 0);
}
elsif ($text=~/misty/i) {
quest::say("Off to Misty Thicket!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(33, -1896, -490, 120.34, 0);
}
elsif ($text=~/south ro/i) {
quest::say("Off to South Ro!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(35, 317, -2034, -22.64, 0);
}
elsif ($text=~/steamfont/i) {
quest::say("Off to Steamfont Mountains!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(56, 1668, -1779, -108.07, 0);
}
elsif ($text=~/toxxulia/i) {
quest::say("Off to Toxxulia Forest!");
$npc->DoAnim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc(56, -357, 1099, -57.93, 0);
}
}
Any optimization tips are more than welcome. Functionality-wise I think I'm there.
ghanja
04-17-2015, 12:24 AM
sub EVENT_SPAWN {
quest::settimer("portershout",90);
}
sub EVENT_TIMER {
if($timer eq "portershout") {
quest::stoptimer("portershout");
quest::shout("Porting to all druid locations! Hail me near tunnel to Qeynos Hills!");
quest::settimer("portershout", int(rand(100))+30);
}
}
sub EVENT_SAY {
my %porthash = (
"butcher" => "Butcherblock Mountains",
"feerrott" => "The Feerrott",
"northkarana" => "North Karana",
"lavastorm" => "Lavastorm Mountains",
"misty" => "Misty Thicket",
"sro" => "South Ro",
"steamfont" => "Steamfont Mountains",
"commons" => "West Commonlands",
"toxxulia" => "Toxxulia Forest"
);
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key})."]");
}
}
elsif (defined $porthash{$text}) {
plugin::Whisper("Off to ".$porthash{$text}." you go!");
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::zone($text);
}
}
sub castdelay{
$delayOver = (time + $_[0]);
while (time < $delayOver){}
1;
}
ghanja
04-17-2015, 12:37 AM
I cannot immediately locate the sound file for ports, however, to give it a little flavor, you could put this before line 34 of the above code snippet (thus making it the new line 34):
$client->PlayMP3("twinkle001_loop.wav");
If you add the above make this line:
castdelay(5);
to
castdelay(9);
To correspond with the length of the wave file.
Asylum
04-17-2015, 05:35 PM
Congratulation on solving your puzzle. Now to tackle simplifying the code. As many have advised over the years, using an array or hash to handle multiple inputs and outputs is the best method to simplify code.
Basically you have a player /say "location" as input to the npc's EVENT_SAY subroutine, which triggers the wonderful spell animations and invis prior to porting to the various destinations as output. The inputs can be stored as a variable $playersaidthis and the outputs as a variable $portplayerhere in an associated array.
Your code will have a single if statement instead of an if/elsif for every destination and be about 90% shorter. Let us know how it works and once again, congratulations on solving your perl puzzle and learning more about scripting.
EDIT: haha, I forgot to hit send this morning and after I realized it this afternoon, ghanja had already posted the script I described.
Kingly_Krab
04-17-2015, 06:44 PM
Here's my work around. This requires my plugin (http://www.eqemulator.org/forums/showthread.php?t=39579) to be useful.
NPC Script: @zones = ("butcher", "feerrott", "northkarana", "lavastorm", "misty", "sro", "steamfont", "commons", "toxxulia");
sub EVENT_SAY {
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go?");
plugin::Whisper(quest::saylink($_, 1, plugin::Zone("LN", $_))) for @zones;
} elsif ($text!~/Hail/i && $text ~~ @zones) {
plugin::Whisper("Give me just a moment to prepare.");
$npc->SetEntityVariable("Client", $client->GetID());
quest::settimer($text, 5);
}
}
sub EVENT_TIMER {
if($timer ~~ @zones) {
quest::stoptimer($timer);
$npc->SignalNPC(plugin::Zone("ID", $timer));
}
}
sub EVENT_SIGNAL {
if (plugin::Zone("SN", $signal) ~~ @zones) {
$entity_list->GetClientByID($npc->GetEntityVariable("Client"))->Message(315, $npc->GetCleanName() . " whispers, 'Off to " . plugin::Zone("LN", $signal) . " you go!'");
$entity_list->GetClientByID($npc->GetEntityVariable("Client"))->SignalClient($entity_list->GetClientByID($npc->GetEntityVariable("Client")), $signal);
}
}Player.pl (required): sub EVENT_SIGNAL {
if ($signal > 0 && $signal < 1000) {
quest::zone(plugin::Zone("SN", $signal));
}
}
markusdabrave
04-17-2015, 07:04 PM
LOL I feel like I won a prize :)
I'm about to give the array thing a try. I'm familiar with them, it's just understanding how Perl handles them. My next question was going to be can you do a case statement but I think you guys have pretty much answered that. I'll let you know how it works out :)
Kingly - Your plugin looks tremendously helpful. Stupid question: How do I use it? Do I need to copy it into the script or can it reside elsewhere as its own script waiting to be called upon?
Kingly_Krab
04-17-2015, 07:06 PM
You need to create a Perl file in your plugins folder in your server folder. Name it whatever you want. Also, Perl has switches, but it's not necessary in this situation, nor have I ever found it necessary.
markusdabrave
04-17-2015, 09:53 PM
sub EVENT_SAY {
my %porthash = (
"butcher" => "Butcherblock Mountains",
"feerrott" => "The Feerrott",
"northkarana" => "North Karana",
"lavastorm" => "Lavastorm Mountains",
"misty" => "Misty Thicket",
"sro" => "South Ro",
"steamfont" => "Steamfont Mountains",
"commons" => "West Commonlands",
"toxxulia" => "Toxxulia Forest"
);
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key})."]");
}
}
elsif (defined $porthash{$text}) {
plugin::Whisper("Off to ".$porthash{$text}." you go!");
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::zone($text);
}
}
Ok this will take me a month to figure out own my own what all's going on here. It works though. So instead of typing a location, you've opted for clickable links. Very clever. It's a little over my head right now but I'll keep staring at it until it sinks in. It sort of does. Is there a way to make the zone list "<zone>, <zone>, <zone>" instead of a list?
About to try KKs. This one's definitely over my head. I've read about globals and entitys but haven't messed with them yet.
Also, side question brought up by the plugin thing:
Could I turn this into a plugin by saving it in the plugins folder?
sub castdelay{
$delayOver = (time + $_[0]);
while (time < $delayOver){}
1;
}
markusdabrave
04-17-2015, 11:57 PM
KK, I'm getting a "<LINKER ERROR>" when I talk to the NPC where he would be listing the port locations. Does the players.pl need to be in plugins or part of the script? I've done something wrong apparently.
Uleat
04-18-2015, 12:05 AM
That 'linker' error may be part of my bailiwick..though, quests are not.
Pretty sure that kicks in when there is missing information in the text link constructor.
I did test scripts to ensure that they worked when I pushed them. (EDIT: pushed the client translation version of the code)
Try having the npc 'say' the information so that you can verify that wrong/null parameters are not being passed.
markusdabrave
04-18-2015, 12:35 AM
quest::say("Hail! Where would you like to go?");
quest::say(quest::saylink($_, 1, plugin::Zone("LN", $_))) for @zones;
Also resulted in the linker error message for each location. Hopefully I did that right.
Side note:
quest::saylink($_, 1, plugin::Zone("LN", $_)) for @zones;
Displays nothing.
markusdabrave
04-18-2015, 12:51 AM
So the ghanja's code works, but it sends me to the zone safe spots rather than the druid ring. Would it make sense to add the x,y,z,h values into the $porthash array and call them in a quest::movenpc rather than a quest::zone command? Something like this:
sub EVENT_SAY {
my %porthash = (
"surefall" => ["Surefall Glade", 3, -391, -209, 4.75, 0],
"butcher" => ["Butcherblock Mountains",68, 1984, -2135, 0],
"feerrott" => ["The Feerrott",47, -1885, 367, 13.57, 0],
"northkarana" => ["North Karana",13, -1494, -2706, -7.5, 0],
"lavastorm" => ["Lavastorm Mountains",27, 460, 460, -84.88, 0],
"misty" => ["Misty Thicket",33, -1896, -490, 120.34, 0],
"sro" => ["South Ro",35, 317, -2034, -22.64, 0],
"steamfont" => ["Steamfont Mountains",56, 1668, -1779, -108.07, 0]
"commons" => ["West Commonlands", 21, 1427, 479, -51, 0],
"toxxulia" => ["Toxxulia Forest", 56, -357, 1099, -57.93, 0],
);
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key})."]");
}
}
elsif (defined $porthash{$text}) {
plugin::Whisper("Off to ".$porthash{$text}." you go!");
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
#quest::zone($text);
quest::movenpc($porthash{$key}[1],[2],[3],[4],[5]);
}
}
... which is broke, probably a syntax thing on my part. This is more a 'am I on a path that makes sense' question. I'm still figuring out hash arrays. I've at least found some references but you know how it is. Reading, doing and understanding are 3 completely different things :)
Uleat
04-18-2015, 12:53 AM
Here is where that text comes from: https://github.com/EQEmu/Server/blob/master/zone/client.cpp#L8394
Let me take your script home tonight to verify that it's not code-related..and hopefully someone will come up with a solution before
I get back tomorrow.
EDIT: Just read your last post..I'll still look it over and see where you are when I get back.
markusdabrave
04-18-2015, 01:26 AM
LOL I don't think I'll make any more progress tonight. As I was reading, there are many ways to do things in Perl. I'm interested in seeing either way :) This is a learning experience for me.
Kingly_Krab
04-18-2015, 01:47 AM
Did you actually create a plugin file in your plugins folder in your base server folder? Mine is C:/EQ/EQEmuServer/plugins, you may have it in something like C:/EQ/EQEmuServer/quests/plugins or C:/EQ/EQEmuServer/quests/global.
Correct folder (C:/EQ/EQEmuServer/plugins):
http://img.prntscr.com/img?url=http://i.imgur.com/H9IZAtk.png
Incorrect folder (C:/EQ/EQEmuServer/quests/plugins or C:/EQ/EQEmuServer/quests/global):
http://img.prntscr.com/img?url=http://i.imgur.com/CaxhTmJ.png
markusdabrave
04-18-2015, 02:03 AM
I think the answer is yes. Sort of. I'm running on linux but I get what you're asking.
My server install is ~/server and there's a symbolic link for plugins there that goes to ~/quests/plugins. So ~/server/plugins points to ~/quests/plugins
So they're one and the same. Or they should be. At any rate, players.pl is there.
eqadmin@eqemu:~/server/plugins$ ls
anim.pl gm_event_say.pl quest_handin.pl
ArcheryAttack.pl group_utility.pl random_message.pl
check_handin.pl guildmasters.pl random_range.pl
check_hasitem.pl illusion_tools.pl random_utils.pl
client_functions.pl Instances.pl soulbinders.pl
client_messages.pl kingley_krab_zonetranslator.pl spawn_tools.pl
constants.pl mob_utils.pl spawn_utils.pl
default-actions.pl MP3.pl Task_Utils.pl
default.pl Multiple_QGlobals.pl text_formatting.pl
DiaWind.pl MySQL.pl time_tools.pl
directional.pl npc_tools.pl utility.pl
Doors_Manip.pl path_tools.pl voicetell.pl
Expeditions.pl players.pl weapon_tools.pl
formation_tools.pl popup_window_utils.pl zone_tools.pl
GetSpawn2IDs.pl Quest_Credit2.pl
globals.pl Quest_Credit.pl
eqadmin@eqemu:~/server/plugins$
eqadmin@eqemu:~/server/quests/plugins$ ls
anim.pl gm_event_say.pl quest_handin.pl
ArcheryAttack.pl group_utility.pl random_message.pl
check_handin.pl guildmasters.pl random_range.pl
check_hasitem.pl illusion_tools.pl random_utils.pl
client_functions.pl Instances.pl soulbinders.pl
client_messages.pl kingley_krab_zonetranslator.pl spawn_tools.pl
constants.pl mob_utils.pl spawn_utils.pl
default-actions.pl MP3.pl Task_Utils.pl
default.pl Multiple_QGlobals.pl text_formatting.pl
DiaWind.pl MySQL.pl time_tools.pl
directional.pl npc_tools.pl utility.pl
Doors_Manip.pl path_tools.pl voicetell.pl
Expeditions.pl players.pl weapon_tools.pl
formation_tools.pl popup_window_utils.pl zone_tools.pl
GetSpawn2IDs.pl Quest_Credit2.pl
globals.pl Quest_Credit.pl
eqadmin@eqemu:~/server/quests/plugins$
Asylum
04-18-2015, 01:50 PM
"So the ghanja's code works, but it sends me to the zone safe spots rather than the druid ring. Would it make sense to add the x,y,z,h values into the $porthash array and call them in a quest::movenpc rather than a quest::zone command?"
You will want to use quest::movepc(zone_id,x,y,z,h) not quest::movenpc because the object you're trying to port is the player character. Just using quest::zone sends to the save coordinates of the zone. Simply run to the druid rings of your destination zone, target yourself, type #loc (NOT /loc unless you like reversing x and y), and use that location in the quest::movepc command. The zone_id portion will accept numbers for the zone IDs or pass it the zone shortname with $text. I haven't searched the plugins folder for it but someone may have made a plugin that converts zone shortname to ID#.
Asylum
04-18-2015, 08:08 PM
As if on cue, thanks Kingly
http://www.eqemulator.org/forums/showthread.php?t=39579
Kingly_Krab
04-18-2015, 08:13 PM
Ah, yeah, I posted that before you posted what you said. No problem.
markusdabrave
04-18-2015, 11:17 PM
"So the ghanja's code works, but it sends me to the zone safe spots rather than the druid ring. Would it make sense to add the x,y,z,h values into the $porthash array and call them in a quest::movenpc rather than a quest::zone command?"
You will want to use quest::movepc(zone_id,x,y,z,h) not quest::movenpc because the object you're trying to port is the player character. Just using quest::zone sends to the save coordinates of the zone. Simply run to the druid rings of your destination zone, target yourself, type #loc (NOT /loc unless you like reversing x and y), and use that location in the quest::movepc command. The zone_id portion will accept numbers for the zone IDs or pass it the zone shortname with $text. I haven't searched the plugins folder for it but someone may have made a plugin that converts zone shortname to ID#.
I'm a derp. Should learn to not write code at 2am probably. I actually had the quest::movepc correct in the quasi-working script. Though trying to use those coordinates in my array has resulted in my NPC not responding (even with the movenpc->movepc fixed). Right now I'm trying to dig up an example of pulling multiple values from an array to see where my syntax went sideways. I'm suspect probably this that's breaking it:
quest::movenpc($porthash{$key}[1],[2],[3],[4],[5]);
Markusdabrave = Perlnoob
Akkadius
04-18-2015, 11:28 PM
1) You have to access the hash elements the same way every single time.
quest::movepc($porthash{$key}[1], $porthash{$key}[2], $porthash{$key}[3], $porthash{$key}[4], $porthash{$key}[5]);
2) The API call is quest::movepc not quest::movenpc
ghanja
04-20-2015, 10:08 PM
Not sure if you made changes yet, but for anyone following the thread:
sub EVENT_SPAWN {
quest::settimer("portershout",90);
}
sub EVENT_TIMER {
if($timer eq "portershout") {
quest::stoptimer("portershout");
quest::shout("Porting to all druid locations! Hail me near tunnel to Qeynos Hills!");
quest::settimer("portershout", int(rand(100))+30);
}
}
sub EVENT_SAY {
my %porthash = (
"surefall" => ["Surefall Glade", 3, -391, -209, 4.75, 0,],
"butcher" => ["Butcherblock Mountains",68, 1984, -2135, 0,],
"feerrott" => ["The Feerrott",47, -1885, 367, 13.57, 0,],
"northkarana" => ["North Karana",13, -1494, -2706, -7.5, 0,],
"lavastorm" => ["Lavastorm Mountains",27, 460, 460, -84.88, 0,],
"misty" => ["Misty Thicket",33, -1896, -490, 120.34, 0,],
"sro" => ["South Ro",35, 317, -2034, -22.64, 0,],
"steamfont" => ["Steamfont Mountains",56, 1668, -1779, -108.07, 0,],
"commons" => ["West Commonlands", 21, 1427, 479, -51, 0,],
"toxxulia" => ["Toxxulia Forest", 56, -357, 1099, -57.93, 0,],
);
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key}[0])."]");
}
}
elsif (defined $porthash{$text}) {
plugin::Whisper("Off to ".$porthash{$text}[0]." you go!");
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
}
sub castdelay{
$delayOver = (time + $_[0]);
while (time < $delayOver){}
1;
}
markusdabrave
04-20-2015, 10:36 PM
I figured it out about 30 minutes ago, then saw your PM. I really appreciate the help from everyone on this. Hopefully I can pay it forward. Here's what I came up with:
sub EVENT_SAY{
my %porthash = (
# line# => [lname, zoneid, x, y, z, heading]
1 => ["Surefall Glade", 3, -391, -209, 4.75, 0 ],
2 => ["Butcherblock Mountains",68, 1984, -2135, 0 ],
3 => ["The Feerrott", 47, -1885, 367, 13.57, 0 ],
4 => ["North Karana", 13, -1494, -2706, -7.5, 0 ],
5 => ["Lavastorm Mountains", 27, 460, 460, -84.88, 0 ],
6 => ["Misty Thicket", 33, -1896, -490, 120.34, 0 ],
7 => ["South Ro", 35, 317, -2034, -22.64, 0 ],
8 => ["Steamfont Mountains", 56, 1668, -1779, -108.07, 0 ],
9 => ["West Commonlands", 21, 1427, 479, -51, 0 ],
10 => ["Toxxulia Forest", 56, -357, 1099, -57.93, 0 ],
);
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key}->[0])."]");
}
}
elsif (defined $porthash{$text}) {
quest::selfcast(34);
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(9);
quest::movepc($porthash{$text}->[1],$porthash{$text}->[2],$porthash{$text}->[3],$porthash{$text}->[4],$porthash{$text}->[5]);
plugin::Whisper("Off to ".$porthash{$text}->[0]." you go!");
}
}
My hash has some extra info in it but that's b/c I played with it a few times. I also stretched the cast delay so the spell effect made more sense aesthetically (at least to me it did). The good news is, I actually understand how hashes work now :) So it's not all Greek anymore.
The last thing I'd like to do with this is make the Superior Camo not be a self-cast (if its possible). Been looking at some other threads about group spells, but technically it's not a group spell. You just have to be in the group for it to land on you.
If there's a way to fake the NPC casting this on the player, I'm all ears:
quest::selfcast(34);
The below works, it just doesn't land on the player (presumably b/c the player is not grouped with the NPC).
$npc->CastSpell(34, $client);
I also messed around with CastGroupSpell but I'm reasonably sure that didn't work b/c this isn't a true group spell (like Group Wolf Form, Talisman of whatever, etc.).
ghanja
04-21-2015, 02:09 PM
Crude as hell, but, hopefully you gain something from it:
sub EVENT_SPAWN {
quest::settimer("portershout",90);
}
sub EVENT_TIMER {
if($timer eq "portershout") {
quest::stoptimer("portershout");
quest::shout("Porting to all druid locations! Hail me near tunnel to Qeynos Hills!");
quest::settimer("portershout", int(rand(100))+30);
}
}
sub EVENT_SAY {
my %porthash = (
"surefall" => ["Surefall Glade", 3, -391, -209, 4.75, 0],
"butcher" => ["Butcherblock Mountains",68, 1984, -2135, 0],
"feerrott" => ["The Feerrott",47, -1885, 367, 13.57, 0],
"northkarana" => ["North Karana",13, -1494, -2706, -7.5, 0],
"lavastorm" => ["Lavastorm Mountains",27, 460, 460, -84.88, 0],
"misty" => ["Misty Thicket",33, -1896, -490, 120.34, 0],
"sro" => ["South Ro",35, 317, -2034, -22.64, 0],
"steamfont" => ["Steamfont Mountains",56, 1668, -1779, -108.07, 0],
"commons" => ["West Commonlands", 21, 1427, 479, -51, 0],
"toxxulia" => ["Toxxulia Forest", 56, -357, 1099, -57.93, 0],
);
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key}[0])."]");
}
}
elsif (defined $porthash{$text}) {
if ($client->IsGrouped()) {
quest::doanim(43);
foreach my $group_member (ClientCloseEnoughGroupMembers($client)) {
$group_member->SpellEffect(43,10);
$npc->SpellFinished(34, $group_member);
}
castdelay(5);
foreach my $group_member (ClientCloseEnoughGroupMembers($client)) {
$group_member->Message (315, "".$npc->GetCleanName()." whispers, 'Off to ".$porthash{$text}[0]." you go!");
$group_member->MovePC($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
}
else {
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
}
}
sub ClientCloseEnoughGroupMembers {
my @return_group;
my $entire_group = $entity_list->GetGroupByClient(shift);
if ($entire_group) {
for ($count = 0; $count < 6; $count++) {
my $group_member = $entire_group->GetMember ($count);
if ($group_member) {
if ($group_member->IsClient()) {
if ($group_member->CalculateDistance($x,$y,$z) <= 30) {
push (@return_group, $group_member);
}
}
}
}
return @return_group;
}
}
sub castdelay{
$delayOver = (time + $_[0]);
while (time < $delayOver){}
1;
}
markusdabrave
04-23-2015, 08:37 PM
Sorry for the time gap. Work and brain melt. Had to take a break. Tried the above code but it seems to only be performing this part of the action:
else {
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
quest::selfcast(34);
quest::movepc($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
Edit:
I'm ok with using the selfcast but if you self-cast and already have the spell it sends an error that the player is already invisible. Is there a way to check for a spell effect active on the player? If there is I could just throw an if statement in there to see if player is already invisible and skip the selfcast if they are. Digging through the lexicon now because I'm not quite sure what I"m searching for.
Edit2:
BreakInvis(); will do. :)
else {
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
$client->BreakInvis();
quest::selfcast(34);
quest::movepc($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
ghanja
04-23-2015, 09:01 PM
Or not even cast it if they already have it, though, breaking the invis would allow for a "fresh" cast, so whichever way you prefer:
sub EVENT_SPAWN {
quest::settimer("portershout",90);
}
sub EVENT_TIMER {
if($timer eq "portershout") {
quest::stoptimer("portershout");
quest::shout("Porting to all druid locations! Hail me near tunnel to Qeynos Hills!");
quest::settimer("portershout", int(rand(100))+30);
}
}
sub EVENT_SAY {
my %porthash = (
"surefall" => ["Surefall Glade", 3, -391, -209, 4.75, 0],
"butcher" => ["Butcherblock Mountains",68, 1984, -2135, 0],
"feerrott" => ["The Feerrott",47, -1885, 367, 13.57, 0],
"northkarana" => ["North Karana",13, -1494, -2706, -7.5, 0],
"lavastorm" => ["Lavastorm Mountains",27, 460, 460, -84.88, 0],
"misty" => ["Misty Thicket",33, -1896, -490, 120.34, 0],
"sro" => ["South Ro",35, 317, -2034, -22.64, 0],
"steamfont" => ["Steamfont Mountains",56, 1668, -1779, -108.07, 0],
"commons" => ["West Commonlands", 21, 1427, 479, -51, 0],
"toxxulia" => ["Toxxulia Forest", 56, -357, 1099, -57.93, 0],
);
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key}[0])."]");
}
}
elsif (defined $porthash{$text}) {
if ($client->IsGrouped()) {
quest::doanim(43);
foreach my $group_member (ClientCloseEnoughGroupMembers($client)) {
$group_member->SpellEffect(43,10);
if (!$group_member->FindBuff(34)) {
$npc->SpellFinished(34, $group_member);
}
}
castdelay(5);
foreach my $group_member (ClientCloseEnoughGroupMembers($client)) {
$group_member->Message (315, "".$npc->GetCleanName()." whispers, 'Off to ".$porthash{$text}[0]." you go!");
$group_member->MovePC($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
}
else {
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
if (!$client->FindBuff(34)) {
$npc->SpellFinished(34, $client);
}
quest::movepc($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
}
}
sub ClientCloseEnoughGroupMembers {
my @return_group;
my $entire_group = $entity_list->GetGroupByClient(shift);
if ($entire_group) {
for ($count = 0; $count < 6; $count++) {
my $group_member = $entire_group->GetMember ($count);
if ($group_member) {
if ($group_member->IsClient()) {
if ($group_member->CalculateDistance($x,$y,$z) <= 30) {
push (@return_group, $group_member);
}
}
}
}
return @return_group;
}
}
sub castdelay{
$delayOver = (time + $_[0]);
while (time < $delayOver){}
1;
}
Though, BreakInvis may also break invis to undead (which you may not care about in your case, but for those following along), I've never tested it against Invis vs Undead.
You can also use:
$client->BuffFadeBySpellID(43);
$group_member->BuffFadeBySpellID(43);
ghanja
04-23-2015, 09:07 PM
Tried the above code but it seems to only be performing this part of the action:
It will if you are not grouped. If you are, then ClientCloseEnoughGroupMembers is checking to see if the other members of your group are within a certain distance (otherwise your script could be exploited).
Edit:
I'm ok with using the selfcast but if you self-cast and already have the spell it sends an error that the player is already invisible. Is there a way to check for a spell effect active on the player? If there is I could just throw an if statement in there to see if player is already invisible and skip the selfcast if they are. Digging through the lexicon now because I'm not quite sure what I"m searching for.
Just make a new post bud, as if I'm on I usually have the F5 key handy.
$client->FindBuff();
Is what you're after, as to finding whether or not a client has a particular buff.
markusdabrave
04-25-2015, 12:43 AM
Thanks to everyone for their help on this. Admittedly, I feel that ghanja did a lot of the heavy lifting here so I'd be remiss to not give credit where credit is due. I mainly built upon his suggestions. Big thanks for all your patience.
Here's the finished product, but first - some notes:
1. This requires the NPC be either a druid or a wizard class. In my case, I added druid NPCs to druid rings and wizard NPCs to wizard spires using this (http://www.eqemulator.org/forums/showthread.php?t=33005)method and slapped this script on them.
2. This ports to old world maps. More specifically, Vanilla EQ original maps (except Lavastorm - working on that). With minor tweaking of the zone ID# and x,y,z,h locations in the %porthash(es) or adding additional zones, it could easily be made to work with other zones. Though if you wanted to, you could add them anywhere you wanted to stick a porter.
3. It automatically casts invis on whoever is being ported (this is to allow evil races to use them with minimal risk of druids eating them).
4. It has spell effects and a small delay for aesthetics.
################################################## #########
# Druid/Wizard NPC Porter Script
sub EVENT_SAY {
# Druid Ports
if ($npc->GetClass() == 6) {
our %porthash = (
"surefall" => ["Surefall Glade", 3, -391, -209, 4.75, 0],
"butcher" => ["Butcherblock Mountains",68, 1984, -2135, 0],
"feerrott" => ["The Feerrott",47, -1885, 367, 13.57, 0],
"northkarana" => ["North Karana",13, -1494, -2706, -7.5, 0],
"lavastorm" => ["Lavastorm Mountains",27, 460, 460, -84.88, 0],
"misty" => ["Misty Thicket",33, -1896, -490, 120.34, 0],
"sro" => ["South Ro",35, 317, -2034, -22.64, 0],
"steamfont" => ["Steamfont Mountains",56, 1668, -1779, -108.07, 0],
"commons" => ["West Commonlands", 21, 1427, 479, -51, 0],
"toxxulia" => ["Toxxulia Forest", 38, -357, 1099, -57.93, 0],
);
}
# Wizard Ports
elsif ($npc->GetClass() == 12) {
our %porthash = (
"toxxulia" => ["Toxxulia Forest", 38, -916, -1510, -37, 0],
"northkarana" => ["North Karana", 13, 1209, -3685, -8.38, 0],
"gfaydark" => ["Greater Faydark", 54, -441, -2023, 0, 0],
"commons" => ["West Commonlands", 21, 1840, -3.85, -15.42, 0],
"nektulos" => ["Nektulos Forest", 25, -768, 432, 33,0],
"nro" => ["North Ro", 34, 823, 1377, 10 ,0],
"cazicthule" => ["Cazic-Thule", 48, -466, 253, 20, 0],
"karana" => ["West Karana", 12, -14815, -3569, 36, 0],
);
}
if ($text=~/Hail/i) {
plugin::Whisper("Hail! Where would you like to go? ");
foreach my $key (keys %porthash) {
$client->Message(315, "[".quest::saylink($key, 1, $porthash{$key}[0])."]");
}
}
elsif (defined $porthash{$text}) {
if ($client->IsGrouped()) {
quest::doanim(43);
foreach my $group_member (ClientCloseEnoughGroupMembers($client)) {
$group_member->SpellEffect(43,10);
if (!$group_member->FindBuff(34)) {
$npc->SpellFinished(34, $group_member);
}
}
castdelay(5);
foreach my $group_member (ClientCloseEnoughGroupMembers($client)) {
$group_member->Message (315, "".$npc->GetCleanName()." whispers, 'Off to ".$porthash{$text}[0]." you go!");
$group_member->MovePC($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
}
else {
quest::doanim(43);
$client->SpellEffect(43,10);
castdelay(5);
if (!$client->FindBuff(34)) {
$npc->SpellFinished(34, $client);
}
quest::movepc($porthash{$text}[1],$porthash{$text}[2],$porthash{$text}[3],$porthash{$text}[4],$porthash{$text}[5]);
}
}
}
sub ClientCloseEnoughGroupMembers {
my @return_group;
my $entire_group = $entity_list->GetGroupByClient(shift);
if ($entire_group) {
for ($count = 0; $count < 6; $count++) {
my $group_member = $entire_group->GetMember ($count);
if ($group_member) {
if ($group_member->IsClient()) {
if ($group_member->CalculateDistance($x,$y,$z) <= 30) {
push (@return_group, $group_member);
}
}
}
}
return @return_group;
}
}
sub castdelay{
$delayOver = (time + $_[0]);
while (time < $delayOver){}
1;
}
If you want your porters to broadcast/shout they are porting, adding the below code will make them shout every 2-3 1/2 minutes. The only thing is you might want to change the Surefall glade NPC's verbiage as it's not really a druid ring (so to speak).
sub EVENT_SPAWN {
quest::settimer("portershout", int(rand(120))+90);
}
sub EVENT_TIMER {
if($timer eq "portershout") {
quest::stoptimer("portershout");
if ($npc->GetClass() == 6) {
quest::shout("Porting to all druid locations! Hail me near druid ring!");
}
elsif($npc->GetClass() == 12){
quest::shout("Porting to all wizard locations! Hail me at wizard spire!");
}
quest::settimer("portershout", int(rand(120))+90);
}
}
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.