Here is a script I made for using while developing. I plan to expand the utilities of it at some point, but currently, it's purpose is to let you set key locs for zones that you might want to be able to move to and from quickly while working on a new zone. You can set it up however you like, but I just made a clicky item that casts a special pet with this script on it from the templates folder.
At the very least, it has an example of a hash of arrays, which might help give people ideas on how to streamline some scripts a bit.
Code:
#GM Utility Script
sub EVENT_SPAWN {
$x = $npc->GetX();
$y = $npc->GetY();
$z = $npc->GetZ();
quest::set_proximity($x - 100, $x + 100, $y - 100, $y + 100, $z - 50, $z + 50);
quest::settimer("setprox", 2);
}
sub EVENT_TIMER {
if ($timer eq "setprox") {
my $x = $npc->GetX();
my $y = $npc->GetY();
my $z = $npc->GetZ();
quest::clear_proximity();
quest::set_proximity($x - 100, $x + 100, $y - 100, $y + 100, $z - 50, $z + 50);
}
}
sub EVENT_SAY {
if ($text =~/Hail/i) {
quest::emote("$qglobals{Dranik_exp}");
}
$refresh = quest::saylink("refresh");
if ($status > 20) {
if($text=~/hail/i) {
plugin::Whisper("Do you want to [$refresh] my proximity?");
}
if($text=~/refresh/i) {
plugin::Whisper("Proxity should begin auto-refreshing again.");
quest::settimer("setprox", 2);
}
}
}
#Hash of arrays to use for setting up GM location lists to easily get around a zone quickly
# Line Number => [ "<zoneshortname#>", "<loc name>", X, Y, Z ],
%CoordNames = (
1 => [ "lopingplains1", "Steamfont Zone In", -3514, -1275, 720 ],
2 => [ "lopingplains2", "Undead Area", 3230, 1310, 400 ],
3 => [ "lopingplains3", "Goblin Camp", -3115, 975, 705 ],
4 => [ "lopingplains4", "Bloodmoon Zone In", 96, -1700, 212 ],
5 => [ "lopingplains5", "Beach Area", -1970, -2890, 39 ],
6 => [ "lopingplains6", "Beach Cliff Camp", -2980, -1975, 268 ],
7 => [ "lopingplains7", "Steed Camp", -2410, 2140, 320 ],
8 => [ "lopingplains8", "Vampire Festival", 1660, 1020, 15 ],
9 => [ "lopingplains9", "Frost Cave", 275, 485, -35 ],
10 => [ "lopingplains10", "Secret Treehouse", 2785, 2340, 340 ],
11 => [ "lopingplains11", "Old Mine", 2990, 275, 335 ],
12 => [ "lopingplains12", "Gem Mine Top", -2835, -45, 558 ],
13 => [ "lopingplains13", "Gem Mine Middle", -2685, 145, 375 ],
14 => [ "lopingplains14", "Gem Mine Bottom", -2690, -720, 195 ],
15 => [ "hillsofshade1", "Base Camp", -444, 470, 54 ],
16 => [ "hillsofshade2", "Grave Yard", -1015, 865, 59 ],
17 => [ "hillsofshade3", "Pirate Camp", -350, 1330, 27 ],
18 => [ "hillsofshade4", "Docks", -515, 1730, 22 ],
19 => [ "hillsofshade5", "Pirate Ship", 85, 2770, 36 ],
20 => [ "hillsofshade6", "Takish Camp", 930, 1385, 44 ],
21 => [ "hillsofshade7", "Spiroc Island", 820, 2111, 14 ],
22 => [ "hillsofshade8", "Raviak Camp", 1910, 1210, 90 ],
23 => [ "hillsofshade9", "Undead Camp", 2000, -30, 8 ],
24 => [ "hillsofshade10", "Outside Undead Goblins", 1135, -295, 6 ],
25 => [ "hillsofshade11", "Undead Goblin Boss", 550, -275, -105 ],
26 => [ "hillsofshade12", "Mushrooms", -1590, -505, -580 ],
27 => [ "stonehive1", "Zone In", -1282, 0, 43 ],
28 => [ "stonehive2", "Maze Left", -925, -640, 45 ],
29 => [ "stonehive3", "Maze Right", -803, 580, 39 ],
30 => [ "stonehive4", "Balcony", 400, 0, 58 ],
31 => [ "stonehive5", "Hive Floor 1", -128, 0, 40 ],
32 => [ "stonehive6", "Hive Floor 2", -77, 0, 287 ],
33 => [ "stonehive7", "Hive Floor 3", 92, 0, 392 ],
34 => [ "stonehive8", "Hive Basement", -23, 29, -54 ],
);
# The $n below is the number currently being checked in the while loop
# $CoordNames{$n}[0]; is Coordinate name for the array and what the saylink will make you say.
# $CoordNames{$n}[1]; is whatever you want the location name to show as in the actual saylink.
# $CoordNames{$n}[2]; is the X coordinate
# $CoordNames{$n}[3]; is the Y coordinate
# $CoordNames{$n}[4]; is the Z coordinate
%Animlist = (
1 => ["kick", 1],
2 => ["pierce", 2],
3 => ["2h slash", 3],
4 => ["2h blunt", 4],
5 => ["2h pierce", 4],
6 => ["throw", 5],
7 => ["offhand", 6],
8 => ["bash", 7],
9 => ["mainhand", 8],
10 => ["bow", 9],
11 => ["swim", 10],
12 => ["round kick", 11],
13 => ["get hit", 12],
14 => ["get hit2", 13],
15 => ["falling", 14],
16 => ["drowning", 15],
17 => ["death", 16],
18 => ["standby", 17],
19 => ["standby2", 18],
20 => ["lunge", 19],
21 => ["jump", 20],
22 => ["falling2", 21],
23 => ["duck walk", 22],
24 => ["ladder climb", 23],
25 => ["crouch", 24],
26 => ["swim2", 25],
27 => ["idle", 26],
28 => ["cheer", 27],
29 => ["disgusted", 28],
30 => ["wave", 29],
31 => ["rude", 30],
32 => ["yawn", 31],
33 => ["move to side", 33],
34 => ["ice slide", 35],
35 => ["kneel", 36],
36 => ["swim3", 37],
37 => ["sit", 38],
38 => ["drumming", 39],
39 => ["guitar", 40],
40 => ["blow horn", 41],
41 => ["cast", 42],
42 => ["cast2", 43],
43 => ["cast3", 44],
44 => ["fly kick", 45],
45 => ["tiger claw", 46],
46 => ["eagle strike", 47],
47 => ["nod yes", 48],
48 => ["shake no", 49],
49 => ["plead", 50],
50 => ["clap", 51],
51 => ["blush", 52],
52 => ["chuckle", 54],
53 => ["cough", 55],
54 => ["scared", 56],
55 => ["head tilt", 57],
56 => ["dance", 58],
57 => ["disagree", 59],
58 => ["glare", 60],
59 => ["peer", 61],
60 => ["kneel", 62],
61 => ["laugh", 63],
62 => ["point", 64],
63 => ["shrug", 65],
64 => ["hand raise", 66],
65 => ["salute", 67],
66 => ["shiver", 68],
67 => ["tap foot", 69],
68 => ["small bow", 70],
69 => ["smile", 77],
70 => ["sec pierce", 85],
71 => ["2h slash2", 87],
72 => ["combat stance", 112],
73 => ["ashamed", 129],
74 => ["cast4", 136],
);
%StanceList = (
1 => ["stand", "standstance", 0],
2 => ["sit", "sitstance", 1],
3 => ["duck", "duckstance", 2],
4 => ["dead", "deadstance", 3],
5 => ["kneel", "kneelstance", 4],
);
sub EVENT_PROXIMITY_SAY {
$move = quest::saylink("move", 0, "move");
$animlist = quest::saylink("animation list");
$stancelist = quest::saylink("stance list");
#$ClientTarget = $client->GetTarget();
#if (!$ClientTarget || $ClientTarget->IsClient()) {
#If no npc target yet, set client target to self for saylinks
# $client->SetTarget($npc);
#}
if ($status > 20) {
#Counts each row for the while
my $count = 0;
#Counts each element in the Array for the while
my $n = 1;
if($text=~/hail/i) {
plugin::Whisper("Options: [$move] [$animlist] [$stancelist]");
}
if($text=~/move/i) {
#Check each line in the hash
while ($CoordNames{$n}[0])
{
#If the first field of the hash array contains the zone short name
if ($CoordNames{$n}[0] =~ lc($zonesn) && $CoordNames{$n}[0] ne lc($text))
{
$count++; #Add to the counter for displaying line numbers in the whisper
#Create the silent saylink
$CoordNameLink = quest::saylink($CoordNames{$n}[0], 0, $CoordNames{$n}[1]);
#List each of the possible options for the current zone
plugin::Whisper("Move Option $count: $zoneln [$CoordNameLink]");
}
$n++;
}
}
if($text=~/animation list/i) {
#Check each line in the hash
while ($Animlist{$n}[0])
{
#Create the silent saylink
$SkillName = quest::saylink($Animlist{$n}[0]);
$SkillID = $Animlist{$n}[1];
#List all animations
plugin::Whisper("Animation: [$SkillName] ID: $SkillID");
$n++;
}
}
if($text=~/stance list/i) {
#Check each line in the hash
while ($StanceList{$n}[0])
{
#Create the silent saylink
$SkillName = quest::saylink($StanceList{$n}[1], 0, $StanceList{$n}[0]);
$SkillID = $StanceList{$n}[2];
#List all Stances
plugin::Whisper("Stance: [$SkillName] ID: $SkillID");
$n++;
}
}
if($text !~ /Hail/i && $text !~ /move/i && $text !~ /animtion list/i && $text !~ /stance list/i) {
my $ClientTarget = $client->GetTarget();
$n = 1;
while ($StanceList{$n}[0])
{
if ($StanceList{$n}[1] eq lc($text))
{
if ($ClientTarget->IsNPC()) {
#Create the silent saylink
$SkillName = quest::saylink($StanceList{$n}[1], 0, $StanceList{$n}[0]);
$SkillID = $StanceList{$n}[2];
$ClientTarget->SetAppearance($SkillID);
#List all animations
plugin::Whisper("Stance: [$SkillName] ID: $SkillID");
return;
}
else {
plugin::Whisper("You must target have a Client or NPC target for the Stance.");
return;
}
}
$n++;
}
$n = 1;
#Check each line in the hash
while ($CoordNames{$n}[0])
{
#If the text said is an exact match to the first field of the hash array
if ($CoordNames{$n}[0] eq lc($text))
{
#Set variables for X, Y, Z and location name
my $NewX = $CoordNames{$n}[2];
my $NewY = $CoordNames{$n}[3];
my $NewZ = $CoordNames{$n}[4];
my $LocName = $CoordNames{$n}[1];
plugin::Whisper("Moving us to $zoneln $NewX, $NewY, $NewZ - $LocName");
#Move the Client and NPC to the new requested location
quest::movepc($zoneid, $NewX, $NewY, $NewZ);
$npc->GMMove($NewX, $NewY, $NewZ);
quest::clear_proximity();
quest::set_proximity($NewX - 100, $NewX + 100, $NewY - 100, $NewY + 100, $NewZ - 50, $NewZ + 50);
return;
}
$n++;
}
#Check the animation list for matching results as well
$n = 1;
while ($Animlist{$n}[0])
{
if ($Animlist{$n}[0] eq lc($text))
{
if ($ClientTarget->IsNPC() || $ClientTarget->IsClient()) {
#Create the silent saylink
$SkillName = quest::saylink($Animlist{$n}[0]);
$SkillID = $Animlist{$n}[1];
#Note that the first field that is hard set to 10 here is actually the speed that the animation will use.
$ClientTarget->DoAnim(10, $SkillID);
#List all animations
plugin::Whisper("Animation: [$SkillName] ID: $SkillID");
return;
}
else {
plugin::Whisper("You must target have a Client or NPC target for the animation.");
return;
}
}
$n++;
}
}
}
}