Log In
Sign Up
Go Gold
Home
Forum
Mail
Downloads
Game Search
Macro Editor
Notes
Membership
formation_tools.pl - Quest File
General Info
Quest File
#Usage: plugin::FollowFormLeader([LeaderMob, OnGrid = 0, MoveToX = 0, MoveToY = 0, NoSpeedBuffs = false]); # This script will move all of 1 NPC Type ID to the relative Guard position that they were the first time this plugin was run # LeaderMob is an optional field where a specific leader NPC can be specified (default is the NPC running the script) # OnGrid is am optional field where 1 will use NPC waypoints if they are on a grid, and 0 (default) will use guard or set XYZ # MoveToX/MoveToY/MoveToZ are optional fields for setting a destination X Y and Z instead of using guard points or way points to determine the destination. # At this time, the MoveToZ field is basically ignored, as the ground Z is calculated based on the leader NPC's Z. # NoSpeedBuffs is an optional field for all speedbuffs to be removed during pathing if enabled sub FollowFormLeader { my $npc = plugin::val('$npc'); my $entity_list = plugin::val('$entity_list'); my $Mob = $_[0]; my $OnGrid = $_[1]; my $MoveToX = $_[2]; my $MoveToY = $_[3]; my $NoSpeedBuffs = $_[4]; if (!$Mob) { $Mob = $npc; } if (!$MoveToX && !$MoveToY && !$MoveToZ) { if (!$OnGrid) { $MoveToX = $Mob->GetGuardPointX(); $MoveToY = $Mob->GetGuardPointY(); } else { $MoveToX = $Mob->GetWaypointX(); $MoveToY = $Mob->GetWaypointY(); } } my $NewHeading = $Mob->CalculateHeadingToTarget($MoveToX, $MoveToY); if ($NoSpeedBuffs) { $Mob->BuffFadeByEffect(3); # Prevent Speed buffs from messing up the group of NPCs } my $LeaderID = $Mob->GetID(); my @npclist = $entity_list->GetNPCList(); foreach $ent (@npclist) { if($ent->EntityVariableExists(52) && $ent->GetEntityVariable(52) == $LeaderID) { #plugin::Debug("Got NPC"); if ($NoSpeedBuffs) { $ent->BuffFadeByEffect(3); # Prevent Speed buffs from messing up the group of NPCs } # Set the Initial Relative Position and Heading variables if(!$ent->EntityVariableExists(50)) { # If this doesn't exist, then neither of them do my $SquadX = $ent->GetX(); my $SquadY = $ent->GetY(); my $SquadHeading = $Mob->CalculateHeadingToTarget($SquadX, $SquadY); my $CurHeading = $Mob->GetHeading(); my $CurDist = plugin::DistNoZ($Mob, $ent); my $HeadingDiff = 0; if ($CurHeading > $SquadHeading) { $HeadingDiff = $CurHeading - $SquadHeading; } else { $HeadingDiff = $CurHeading + 256 - $SquadHeading; } $ent->SetEntityVariable(50, $CurDist); # Original Distance from Leader $ent->SetEntityVariable(51, $HeadingDiff); # Original Heading Difference from Leader } my $SquadDist = $ent->GetEntityVariable(50); my $HDiff = $ent->GetEntityVariable(51); #plugin::Debug("Got Variables"); my $NewSquadHeading = 0; if ($NewHeading - $HDiff > 0) { $NewSquadHeading = $NewHeading - $HDiff; } else { $NewSquadHeading = 256 + $NewHeading - $HDiff; } #plugin::Debug("Before Calc"); my @DestArray = plugin::CalcDestFromHeadingXY($NewSquadHeading, $SquadDist, $MoveToX, $MoveToY, 10, $Mob); my $NewX = $DestArray[0]; my $NewY = $DestArray[1]; my $NewZ = $DestArray[2]; #plugin::Debug("After Calc"); $ent->MoveTo($NewX, $NewY, $NewZ, $NewHeading, 1); #plugin::Debug("Moving NPC"); } } } #Usage: plugin::MoveInFormation(NPCID, [$npc = 0, OnGrid = 0, MoveToX = 0, MoveToY = 0, NoSpeedBuffs = false]); # This script will move all of 1 NPC Type ID to the relative Guard position that they were the first time this plugin was run # NPCID is the NPC ID of the NPCs you want to move in the formation (moves all of this NPC ID in the whole zone) # $npc is an optional field where a specific leader NPC can be specified (default is the NPC running the script) # OnGrid is am optional field where 1 will use NPC waypoints if they are on a grid, and 0 (default) will use guard or set XYZ # MoveToX/MoveToY/MoveToZ are optional fields for setting a destination X Y and Z instead of using guard points or way points to determine the destination. # At this time, the MoveToZ field is basically ignored, as the ground Z is calculated based on the leader NPC's Z. # NoSpeedBuffs is an optional field for all speedbuffs to be removed during pathing if enabled sub MoveInFormation { my $npc = plugin::val('$npc'); my $entity_list = plugin::val('$entity_list'); my $SquadNPCID = $_[0]; my $Mob = $_[1]; my $OnGrid = $_[2]; my $MoveToX = $_[3]; my $MoveToY = $_[4]; my $NoSpeedBuffs = $_[5]; if (!$Mob) { $Mob = $npc; } if (!$MoveToX && !$MoveToY && !$MoveToZ) { if (!$OnGrid) { $MoveToX = $Mob->GetGuardPointX(); $MoveToY = $Mob->GetGuardPointY(); #$MoveToZ = $Mob->GetGuardPointZ(); #plugin::Debug("Using Guard Locs"); } else { #GetWaypointX(), GetWaypointY(), GetWaypointZ(), GetWaypointH(), GetWaypointPause(), and GetWaypointID(). #$Mob->CalculateNewWaypoint(); #my $WPID = int($Mob->GetWaypointID()); #my $WPPause = int($Mob->GetWaypointPause()); #my $CurX = int($Mob->GetX()); #my $CurY = int($Mob->GetY()); $MoveToX = $Mob->GetWaypointX(); $MoveToY = $Mob->GetWaypointY(); #$MoveToZ = $Mob->GetWaypointZ(); #plugin::Debug("Using WP:$WPID Pause:$WPPause WPX:$MoveToX WPY:$MoveToY CurX:$CurX CurY:$CurY"); } } my $NewHeading = $Mob->CalculateHeadingToTarget($MoveToX, $MoveToY); if ($NoSpeedBuffs) { $Mob->BuffFadeByEffect(3); # Prevent Speed buffs from messing up the group of NPCs } my @npclist = $entity_list->GetNPCList(); foreach $ent (@npclist) { if($ent->GetNPCTypeID() == $SquadNPCID) { #plugin::Debug("Got NPC"); if ($NoSpeedBuffs) { $ent->BuffFadeByEffect(3); # Prevent Speed buffs from messing up the group of NPCs } # Set the Initial Relative Position and Heading variables if(!$ent->EntityVariableExists(50)) { # If this doesn't exist, then neither of them do my $SquadX = $ent->GetX(); my $SquadY = $ent->GetY(); my $SquadHeading = $Mob->CalculateHeadingToTarget($SquadX, $SquadY); my $CurHeading = $Mob->GetHeading(); my $CurDist = plugin::DistNoZ($Mob, $ent); my $HeadingDiff = 0; if ($CurHeading > $SquadHeading) { $HeadingDiff = $CurHeading - $SquadHeading; } else { $HeadingDiff = $CurHeading + 256 - $SquadHeading; } $ent->SetEntityVariable(50, $CurDist); # Original Distance from Leader $ent->SetEntityVariable(51, $HeadingDiff); # Original Heading Difference from Leader } my $SquadDist = $ent->GetEntityVariable(50); my $HDiff = $ent->GetEntityVariable(51); #plugin::Debug("Got Variables"); my $NewSquadHeading = 0; if ($NewHeading - $HDiff > 0) { $NewSquadHeading = $NewHeading - $HDiff; } else { $NewSquadHeading = 256 + $NewHeading - $HDiff; } #plugin::Debug("Before Calc"); my @DestArray = plugin::CalcDestFromHeadingXY($NewSquadHeading, $SquadDist, $MoveToX, $MoveToY, 10, $Mob); my $NewX = $DestArray[0]; my $NewY = $DestArray[1]; my $NewZ = $DestArray[2]; #plugin::Debug("After Calc"); $ent->MoveTo($NewX, $NewY, $NewZ, $NewHeading, 1); #plugin::Debug("Moving NPC"); } } } #Usage: plugin::MoveToFormation(NPCID, LeaderMob, Distance, Columns, Rows, [LeadDist, MaxZDiff]); # NPCID is the NPC Type ID of the NPCs you want to form the squad formation with # LeaderMob is the Client or NPC you want to spawn the formation behind (use invisible and/or temp NPC to show no leader) # Distance is the distance each member of the formation will be from each other on both axis # Columns is the number of columns you want in the formation # Rows is the number of rows you want in the formation # LeadDist is the distance you want the formation to be created behind the leader # MaxZDiff is the maximum height above the leader that the best Z will be searched for sub MoveToFormation { my $NPCID = $_[0]; my $Mob = $_[1]; my $Distance = $_[2]; my $Columns = $_[3]; my $Rows = $_[4]; my $LeadDist = $_[5]; my $MaxZDiff = $_[6]; if (!$MaxZDiff) { $MaxZDiff = 15; } if (!$LeadDist) { $LeadDist = $Distance; } my $npc = plugin::val('$npc'); my $client = plugin::val('$client'); my $entity_list = plugin::val('$entity_list'); if (!$Mob) { if ($npc->IsNPC()) { $Mob = $npc; } elsif ($client->IsClient()) { $Mob = $client; } else { return; # No Client or NPC found } } my $SpawnX = $Mob->GetX(); my $SpawnY = $Mob->GetY(); my $SpawnZ = $Mob->GetZ(); my $LeaderHeading = $Mob->GetHeading(); $SpawnX = $SpawnX + $LeadDist; $SpawnY = $SpawnY - (($Columns - 1) * $Distance / 2); my $NewX = $SpawnX; my $NewY = $SpawnY; my @npclist = $entity_list->GetNPCList(); my @SquadNPCs = (); # Creates a cleared array foreach $ent (@npclist) { if($ent->GetNPCTypeID() == $NPCID) { #plugin::Debug("Found a matching NPC"); push(@SquadNPCs, $ent->GetID()); # Adds an element to the end of the array #plugin::Debug("Added the NPC to the list"); } } my $ArrayEntry = 0; for ($ColNum = 0; $ColNum < $Columns; $ColNum++) { #plugin::Debug("Column $ColNum"); for ($RowNum = 0; $RowNum < $Rows; $RowNum++) { #plugin::Debug("Row $RowNum"); my $SquadHeading = $Mob->CalculateHeadingToTarget($NewX, $NewY); my $CurDist = plugin::DistNoZToCoords($Mob, $NewX, $NewY); my $DestH = 0; if ($LeaderHeading > ($SquadHeading - 64)) { $DestH = $LeaderHeading - $SquadHeading - 64; } else { $DestH = 256 + $LeaderHeading - $SquadHeading - 64; } my @DestArray = plugin::CalcDestFromHeading($DestH, $CurDist, $Mob, $MaxZDiff); my $DestX = $DestArray[0]; my $DestY = $DestArray[1]; my $DestZ = $DestArray[2]; my $ArrayNPC = $SquadNPCs[$ArrayEntry]; my $CurNPC = $entity_list->GetNPCByID($ArrayNPC); $CurNPC->MoveTo($DestX, $DestY, $DestZ, $LeaderHeading, 1); my $NewSquadHeading = $Mob->CalculateHeadingToTarget($DestX, $DestY); my $HeadingDiff = 0; if ($LeaderHeading > $NewSquadHeading) { $HeadingDiff = $LeaderHeading - $NewSquadHeading; } else { $HeadingDiff = $LeaderHeading + 256 - $NewSquadHeading; } $CurNPC->SetEntityVariable(50, $CurDist); # Original Distance from Leader $CurNPC->SetEntityVariable(51, $HeadingDiff); # Original Heading Difference from Leader $NewX = $NewX + $Distance; $ArrayEntry++; } $NewY = $NewY + $Distance; $NewX = $SpawnX; } } #Usage: plugin::RandomFormRoam(MaxVariance, MaxZVariance, LoSMobSize); # NPCID is the NPC Type ID of the NPCs you want to form the squad formation with # MaxVariance - Sets the max X/Y variance to travel # MaxZVariance - Sets the max Z variance to travel. This field is optional and default is 15. # LoSMobSize - Sets the size of the mob LoS check. This field is optional and default is 5. # The LoS check basically looks from your NPC to an imaginary NPC of the LoSMobSize size to see if LoS exists sub RandomFormRoam { my $npc = plugin::val('$npc'); my $entity_list = plugin::val('$entity_list'); #my $NPCID = $_[0]; my $MaxVariance = $_[0]; my $MaxZVariance = $_[1]; my $LoSMobSize = $_[2]; #Set the Max Z Variance to 15 if no 3rd argument is set if(!$MaxZVariance) { $MaxZVariance = 15; } #Set the LoS Check Mob Size to 5 if no 4th argument is set if(!$LoSMobSize) { $LoSMobSize = 5; } # Don't try to roam if already engaged in combat! if ($npc->IsEngaged() != 1) { #Get needed Locs my $CurX = $npc->GetX(); my $CurY = $npc->GetY(); #my $CurZ = $npc->GetZ(); #Not currently required by this plugin my $OrigX = $npc->GetSpawnPointX(); my $OrigY = $npc->GetSpawnPointY(); my $OrigZ = $npc->GetSpawnPointZ(); my $GuardX = $npc->GetGuardPointX(); my $GuardY = $npc->GetGuardPointY(); if ($CurX == $GuardX && $CurY == $GuardY) { #If the NPC has finished walking to the previous given Loc #plugin::Debug("My Guard X is $GuardX and Y is $GuardY"); #Get a random X and Y within the set range my $RandomX = int(rand($MaxVariance - 1)) + 1; my $RandomY = int(rand($MaxVariance - 1)) + 1; my $PosX = $OrigX + $RandomX; my $PosY = $OrigY + $RandomY; my $NegX = $OrigX - $RandomX; my $NegY = $OrigY - $RandomY; my $NewX = quest::ChooseRandom($PosX, $NegX); my $NewY = quest::ChooseRandom($PosY, $NegY); #Check for LoS and Z issues before moving to the new Loc my $NewZ = $npc->FindGroundZ($NewX,$NewY, 5) + 1; #Add 1 to the new Z to prevent hopping issue when they arrive if ($NewZ > -999999 && $OrigZ > ($NewZ - $MaxZVariance + 1) && $OrigZ < ($NewZ + $MaxZVariance - 1)) { my $NewH = $npc->CalculateHeadingToTarget($NewX, $NewY); my $LoS_Check = $npc->CheckLoSToLoc($NewX, $NewY, $NewZ, $LoSMobSize); #Check LoS to the new random Loc if ($LoS_Check) { quest::moveto($NewX, $NewY, $NewZ, $NewH, 1); #plugin::MoveInFormation($NPCID, $npc, 0, $NewX, $NewY); plugin::FollowFormLeader($npc, 0, $NewX, $NewY); } else { # If the NPC is not at its spawn point, return to it to prevent getting stuck if ($OrigX != $CurX || $OrigY != $CurY) { quest::moveto($OrigX, $OrigY, $OrigZ, $NewH, 1); plugin::FollowFormLeader($npc, 0, $NewX, $NewY); } } } } } } #Usage: plugin::SpawnInFormation(NPCID, LeaderMob, Distance, Columns, Rows, [LeadDist, MaxZDiff]); # NPCID is the NPC Type ID of the NPCs you want to form the squad formation with # LeaderMob is the Client or NPC you want to spawn the formation behind (use invisible and/or temp NPC to show no leader) # Distance is the distance each member of the formation will be from each other on both axis # Columns is the number of columns you want in the formation # Rows is the number of rows you want in the formation # LeadDist is the distance you want the formation to be created behind the leader # MaxZDiff is the maximum height above the leader that the best Z will be searched for sub SpawnInFormation { my $NPCID = $_[0]; my $Mob = $_[1]; my $Distance = $_[2]; my $Columns = $_[3]; my $Rows = $_[4]; my $LeadDist = $_[5]; my $MaxZDiff = $_[6]; if (!$MaxZDiff) { $MaxZDiff = 15; } if (!$LeadDist) { $LeadDist = $Distance; } my $npc = plugin::val('$npc'); my $client = plugin::val('$client'); my $entity_list = plugin::val('$entity_list'); if (!$Mob) { if ($npc->IsNPC()) { $Mob = $npc; } elsif ($client->IsClient()) { $Mob = $client; } else { return; # No Client or NPC found } } my $SpawnX = $Mob->GetX(); my $SpawnY = $Mob->GetY(); my $SpawnZ = $Mob->GetZ(); my $LeaderHeading = $Mob->GetHeading(); $SpawnX = $SpawnX + $LeadDist; $SpawnY = $SpawnY - (($Columns - 1) * $Distance / 2); my $NewX = $SpawnX; my $NewY = $SpawnY; for ($ColNum = 0; $ColNum < $Columns; $ColNum++) { #plugin::Debug("Column $ColNum"); for ($RowNum = 0; $RowNum < $Rows; $RowNum++) { #plugin::Debug("Row $RowNum"); my $SquadHeading = $Mob->CalculateHeadingToTarget($NewX, $NewY); my $CurDist = plugin::DistNoZToCoords($Mob, $NewX, $NewY); my $DestH = 0; if ($LeaderHeading > ($SquadHeading - 64)) { $DestH = $LeaderHeading - $SquadHeading - 64; } else { $DestH = 256 + $LeaderHeading - $SquadHeading - 64; } my @DestArray = plugin::CalcDestFromHeading($DestH, $CurDist, $Mob, $MaxZDiff); my $DestX = $DestArray[0]; my $DestY = $DestArray[1]; my $DestZ = $DestArray[2]; my $EntityID = quest::spawn2($NPCID, 0, 0, $DestX, $DestY, $DestZ, $LeaderHeading); my $CurNPC = $entity_list->GetNPCByID($EntityID); my $NewSquadHeading = $Mob->CalculateHeadingToTarget($DestX, $DestY); my $HeadingDiff = 0; if ($LeaderHeading > $NewSquadHeading) { $HeadingDiff = $LeaderHeading - $NewSquadHeading; } else { $HeadingDiff = $LeaderHeading + 256 - $NewSquadHeading; } my $LeaderID = $Mob->GetID(); $CurNPC->SetEntityVariable(50, $CurDist); # Original Distance from Leader $CurNPC->SetEntityVariable(51, $HeadingDiff); # Original Heading Difference from Leader $CurNPC->SetEntityVariable(52, $LeaderID); # Save the entity ID of the leader NPC $NewX = $NewX + $Distance; } $NewY = $NewY + $Distance; $NewX = $SpawnX; } } #Usage: plugin::SpawnInFormationXY(NPCID, X, Y, Z, Distance, Columns, Rows, Heading, MaxZDiff); # NPCID is the NPC Type ID of the NPCs you want to form the squad formation with # X/Y/Z are the coords of the first NPC to spawn that the others are spawned based on it's location # Distance is the distance each member of the formation will be from each other on both axis # Columns is the number of columns you want in the formation # Rows is the number of rows you want in the formation # Heading is heading for the spawns to face # MaxZDiff is the maximum height above the leader that the best Z will be searched for sub SpawnInFormationXY { my $NPCID = $_[0]; my $SpawnX = $_[1]; my $SpawnY = $_[2]; my $SpawnZ = $_[3]; my $Distance = $_[4]; my $Columns = $_[5]; my $Rows = $_[6]; my $Heading = $_[7]; my $MaxZDiff = $_[8]; if (!$Heading) { $Heading = 0; } if (!$MaxZDiff) { $MaxZDiff = 15; } my $entity_list = plugin::val('$entity_list'); $SpawnX = $SpawnX + $Distance; $SpawnY = $SpawnY - (($Columns - 1) * $Distance / 2); # Spawn the first NPC quest::spawn2($NPCID, 0, 0, $SpawnX, $SpawnY, $SpawnZ, $Heading); #plugin::Debug("Spawned First NPC"); # Get the first NPC my $MainNPC = $entity_list->GetNPCByNPCTypeID($NPCID); #plugin::Debug("Got First NPC"); my $NewX = $SpawnX; my $NewY = $SpawnY; #my $RowNum = 1; # Prevent Respawn over the first NPC $NewX = $NewX + $Distance; if ($MainNPC) { for ($ColNum = 0; $ColNum < $Columns; $ColNum++) { #plugin::Debug("Column $ColNum"); for ($RowNum = 0; $RowNum < $Rows; $RowNum++) { # Prevent Respawn over the first NPC if ($RowNum > 0 || $ColNum > 0) { #plugin::Debug("Row $RowNum"); my $NewZ = $MainNPC->FindGroundZ($NewX, $NewY, $MaxZDiff); quest::spawn2($NPCID, 0, 0, $NewX, $NewY, $NewZ, $Heading); $NewX = $NewX + $Distance; } } $NewY = $NewY + $Distance; $NewX = $SpawnX; } } } #Usage: plugin::SpawnMixedFormation(LeaderMob, Distance, Columns, Rows, LeadDist=Distance, MaxZDiff=15, NPCID, NPCID...); # Works just like SpawnInFormation, accept this allows mixing multiple NPCs into the formation # Can add as many NPCIDs as wanted by appending to the end of the arguments # NPCID is the NPC Type ID of the NPCs you want to form the squad formation with # LeaderMob is the Client or NPC you want to spawn the formation behind (use invisible and/or temp NPC to show no leader) # Distance is the distance each member of the formation will be from each other on both axis # Columns is the number of columns you want in the formation # Rows is the number of rows you want in the formation # LeadDist is the distance you want the formation to be created behind the leader # MaxZDiff is the maximum height above the leader that the best Z will be searched for sub SpawnMixedFormation { my $Mob = $_[0]; my $Distance = $_[1]; my $Columns = $_[2]; my $Rows = $_[3]; my $LeadDist = $_[4]; my $MaxZDiff = $_[5]; if (!$MaxZDiff) { $MaxZDiff = 15; } if (!$LeadDist) { $LeadDist = $Distance; } if(!$_[6]) { plugin::Debug("At least 1 NPCID is required for SpawnMixedFormation plugin!"); } my $LastArg = 6; while($_[$LastArg]) { $LastArg++; } $LastArg--; my $npc = plugin::val('$npc'); my $client = plugin::val('$client'); my $entity_list = plugin::val('$entity_list'); if (!$Mob) { if ($npc->IsNPC()) { $Mob = $npc; } elsif ($client->IsClient()) { $Mob = $client; } else { return; # No Client or NPC found } } my $SpawnX = $Mob->GetX(); my $SpawnY = $Mob->GetY(); my $SpawnZ = $Mob->GetZ(); my $LeaderHeading = $Mob->GetHeading(); $SpawnX = $SpawnX + $LeadDist; $SpawnY = $SpawnY - (($Columns - 1) * $Distance / 2); my $NewX = $SpawnX; my $NewY = $SpawnY; for ($ColNum = 0; $ColNum < $Columns; $ColNum++) { #plugin::Debug("Column $ColNum"); for ($RowNum = 0; $RowNum < $Rows; $RowNum++) { #plugin::Debug("Row $RowNum"); my $SquadHeading = $Mob->CalculateHeadingToTarget($NewX, $NewY); my $CurDist = plugin::DistNoZToCoords($Mob, $NewX, $NewY); my $DestH = 0; if ($LeaderHeading > ($SquadHeading - 64)) { $DestH = $LeaderHeading - $SquadHeading - 64; } else { $DestH = 256 + $LeaderHeading - $SquadHeading - 64; } my @DestArray = plugin::CalcDestFromHeading($DestH, $CurDist, $Mob, $MaxZDiff); my $DestX = $DestArray[0]; my $DestY = $DestArray[1]; my $DestZ = $DestArray[2]; my $RandomNPCIDArg = plugin::RandomRange(6, $LastArg); my $NPCID = $_[$RandomNPCIDArg]; my $EntityID = quest::spawn2($NPCID, 0, 0, $DestX, $DestY, $DestZ, $LeaderHeading); my $CurNPC = $entity_list->GetNPCByID($EntityID); my $NewSquadHeading = $Mob->CalculateHeadingToTarget($DestX, $DestY); my $HeadingDiff = 0; if ($LeaderHeading > $NewSquadHeading) { $HeadingDiff = $LeaderHeading - $NewSquadHeading; } else { $HeadingDiff = $LeaderHeading + 256 - $NewSquadHeading; } my $LeaderID = $Mob->GetID(); $CurNPC->SetEntityVariable(50, $CurDist); # Original Distance from Leader $CurNPC->SetEntityVariable(51, $HeadingDiff); # Original Heading Difference from Leader $CurNPC->SetEntityVariable(52, $LeaderID); # Save the entity ID of the leader NPC $NewX = $NewX + $Distance; } $NewY = $NewY + $Distance; $NewX = $SpawnX; } } #Usage: plugin::FollowInFormation(NPCID, Mob, [MaxZDiff]); # This script will move all of 1 NPC Type ID to the relative Guard position that they were the first time this plugin was run # NPCID is the NPC ID of the NPCs you want to move in the formation (moves all of this NPC ID in the whole zone) # Mob is the leader NPC that you want the NPCs to follow in formation # MaxZDiff is an optional field (default of 30) to set the Max Z the NPCs will check to find the ground Z location sub FollowInFormation { my $entity_list = plugin::val('$entity_list'); my $SquadNPCID = $_[0]; my $Mob = $_[1]; my $MaxZDiff = $_[2]; my $MoveToX = $Mob->GetX(); my $MoveToY = $Mob->GetY(); if(!$MaxZDiff) { $MaxZDiff = 15; } #my $NewHeading = $Mob->CalculateHeadingToTarget($MoveToX, $MoveToY); my $NewHeading = $Mob->GetHeading(); my $RunSpeed = 0; my @npclist = $entity_list->GetNPCList(); foreach $ent (@npclist) { if($ent->GetNPCTypeID() == $SquadNPCID) { # Set the Initial Relative Position and Heading variables if(!$ent->EntityVariableExists(50)) { # If this doesn't exist, then neither of them do my $SquadX = $ent->GetX(); my $SquadY = $ent->GetY(); my $SquadHeading = $Mob->CalculateHeadingToTarget($SquadX, $SquadY); my $CurHeading = $Mob->GetHeading(); my $StartDist = plugin::DistNoZ($Mob, $ent); my $HeadingDiff = 0; if ($CurHeading > $SquadHeading) { $HeadingDiff = $CurHeading - $SquadHeading; } else { $HeadingDiff = $CurHeading + 256 - $SquadHeading; } $ent->SetEntityVariable(50, $StartDist); # Original Distance from Leader $ent->SetEntityVariable(51, $HeadingDiff); # Original Heading Difference from Leader } my $SquadDist = $ent->GetEntityVariable(50); my $HDiff = $ent->GetEntityVariable(51); #plugin::Debug("Got Variables"); #Set Run Speed depending on distance from the leader if(!$RunSpeed) { my $CurDist = plugin::DistNoZ($Mob, $ent); if ($CurDist > ($SquadDist * 10)) { $RunSpeed = 5; } elsif($CurDist > ($SquadDist * 5)) { $RunSpeed = 3; } else { $RunSpeed = 1.25; } } $ent->ModifyNPCStat("runspeed", $RunSpeed); my $NewSquadHeading = 0; if ($NewHeading - $HDiff > 0) { $NewSquadHeading = $NewHeading - $HDiff; } else { $NewSquadHeading = 256 + $NewHeading - $HDiff; } #plugin::Debug("Before Calc"); #Usage: my @DestArray = plugin::CalcDestFromHeadingXY(Heading, Distance, X, Y, [MaxZDiff, Mob]); my @DestArray = plugin::CalcDestFromHeadingXY($NewSquadHeading, $SquadDist, $MoveToX, $MoveToY, $MaxZDiff, $Mob); my $NewX = $DestArray[0]; my $NewY = $DestArray[1]; my $NewZ = $DestArray[2]; #plugin::Debug("After Calc"); $ent->MoveTo($NewX, $NewY, $NewZ, $NewHeading, 1); #plugin::Debug("Moving NPC"); } } } #Usage: plugin::SquadAttackTarget(SquadNPCID, TargetID); # Squad1NPCID is the NPC ID of the Squad attacking the other # TargetID is the Entity ID of the Target being attacked sub SquadAttackTarget { my $entity_list = plugin::val('$entity_list'); my $SquadNPCID = $_[0]; my $TargetID = $_[1]; my $TargetNPC = $entity_list->GetNPCByID($TargetID); # Gets the NPC from the array if ($TargetNPC) { if($TargetNPC->EntityVariableExists(50)) # If this exists, the target is part of a squad { # Have the squad attack the other squad my $TargetNPCID = $TargetNPC->GetNPCTypeID(); plugin::SquadAttackSquad($SquadNPCID, $TargetNPCID); } else { my @npclist = $entity_list->GetNPCList(); foreach $ent (@npclist) { # Have the squad attack the single target if($ent->GetNPCTypeID() == $SquadNPCID) { $ent->AddToHateList($TargetNPC, 1); } } } } } #Usage: plugin::SquadAttackSquad(Squad1NPCID, Squad2NPCID); # Squad1NPCID is the NPC ID of the Squad attacking the other squad # Squad2NPCID is the NPC ID of the Squad being attacked sub SquadAttackSquad { my $entity_list = plugin::val('$entity_list'); my $SquadNPCID1 = $_[0]; my $SquadNPCID2 = $_[1]; my @npclist = $entity_list->GetNPCList(); my @Squad1 = (); # Creates a cleared array my @Squad2 = (); # Creates a cleared array foreach $ent (@npclist) { if($ent->GetNPCTypeID() == $SquadNPCID1) { push(@Squad1, $ent->GetID()); # Adds an element to the end of the array } if($ent->GetNPCTypeID() == $SquadNPCID2) { push(@Squad2, $ent->GetID()); # Adds an element to the end of the array } } my $ArraySize1 = @Squad1; my $ArraySize2 = @Squad2; #plugin::Debug("Squad1: $ArraySize1, Squad2: $ArraySize2"); foreach $EntID (@Squad1) { if ($EntID) { my $GotSquadNPC = $entity_list->GetNPCByID($EntID); # Gets the NPC from the array my $RandNPC = plugin::RandomRange(0, $ArraySize2); # Pick one of the chosen NPCs my $GotNPC2 = $entity_list->GetNPCByID($Squad2[$RandNPC]); # Gets the NPC from the array #AddToHateList(other, hate= 0, damage= 0, iYellForHelp= true, bFrenzy= false, iBuffTic= false) if ($GotNPC2 && $GotNPC2->IsNPC()) { $GotSquadNPC->AddToHateList($GotNPC2, 1, 0, 0); } else { my $GotNPCDefault = $entity_list->GetNPCByID($Squad2[0]); # Gets the NPC from the array $GotSquadNPC->AddToHateList($GotNPCDefault, 1, 0, 0); } } } } return 1; #This line is required at the end of every plugin file in order to use it #Usage: my @DestArray = plugin::CalcDestFromHeading(Heading, Distance, [Mob, MaxZDiff]); # This plugin calculates the destination X and Y loc based on heading and distance # Heading is the heading you want to calculate destination X Y Z from # Distance is the distance you want for the destination X and Y from the source # Mob is an optional field to allow any mob to be set, but $npc is default # MaxZDiff is the max height difference from the source mob's Z you want to calculate the destination from. # # The output array can be used as follows: # my $DestX = $DestArray[0]; # my $DestY = $DestArray[1]; # my $DestZ = $DestArray[2]; sub CalcDestFromHeading { my $npc = plugin::val('$npc'); my $Heading = $_[0]; my $Distance = $_[1]; my $Mob = $_[2]; my $MaxZDiff = $_[3]; if (!$Distance) { return; } if (!$Mob) { $Mob = $npc; } if (!$MaxZDiff) { $MaxZDiff = 50; } my $ReverseHeading = 256 - $Heading; my $ConvertAngle = $ReverseHeading * 1.40625; if ($ConvertAngle <= 270) { $ConvertAngle = $ConvertAngle + 90; } else { $ConvertAngle = $ConvertAngle - 270; } my $Radian = $ConvertAngle * (3.1415927 / 180); my $CircleX = $Distance * cos($Radian); my $CircleY = $Distance * sin($Radian); my $DestX = $CircleX + $Mob->GetX(); my $DestY = $CircleY + $Mob->GetY(); my $DestZ = $Mob->FindGroundZ($DestX, $DestY, $MaxZDiff); my @DestArray = ($DestX, $DestY, $DestZ); return @DestArray; } #Usage: my @DestArray = plugin::CalcDestFromHeadingXY(Heading, Distance, X, Y, [MaxZDiff, Mob]); # This plugin calculates the destination X and Y loc based on heading and distance # Heading is the heading you want to calculate destination X Y Z from # Distance is the distance you want for the destination X and Y from the source # X is the X loc that the destination will be calculated from # Y is the Y loc that the destination will be calculated from # MaxZDiff is the max height difference from the source mob's Z you want to calculate the destination from. # # The output array can be used as follows: # my $DestX = $DestArray[0]; # my $DestY = $DestArray[1]; # my $DestZ = $DestArray[2]; sub CalcDestFromHeadingXY { my $npc = plugin::val('$npc'); my $client = plugin::val('$client'); my $Heading = $_[0]; my $Distance = $_[1]; my $MobX = $_[2]; my $MobY = $_[3]; my $MaxZDiff = $_[4]; my $Mob = $_[5]; if (!$Mob) { if ($npc->IsNPC()) { $Mob = $npc; } elsif ($client->IsClient()) { $Mob = $client; } else { return; # No Client or NPC found } } if (!$Distance) { return; } if (!$MaxZDiff) { $MaxZDiff = 50; } my $ReverseHeading = 256 - $Heading; my $ConvertAngle = $ReverseHeading * 1.40625; if ($ConvertAngle <= 270) { $ConvertAngle = $ConvertAngle + 90; } else { $ConvertAngle = $ConvertAngle - 270; } my $PI = 3.141592653589793238; my $Radian = $ConvertAngle * ($PI / 180); my $CircleX = $Distance * cos($Radian); my $CircleY = $Distance * sin($Radian); my $DestX = $CircleX + $MobX; my $DestY = $CircleY + $MobY; my $DestZ = $Mob->FindGroundZ($DestX, $DestY, $MaxZDiff); my @DestArray = ($DestX, $DestY, $DestZ); return @DestArray; } #Usage: plugin::GetReverseHeading($mob); # Returns the heading of the opposite direction the mob is facing sub GetReverseHeading { my $Mob = $_[0]; my $CurHeading = $Mob->GetHeading(); my $ReverseHeading = 128 + $CurHeading; if ($ReverseHeading >= 256) { $ReverseHeading = $ReverseHeading - 256; } return $ReverseHeading; } #Usage: my $Degrees = plugin::ConvertHeadingToDegrees(Heading); # Converts 0-256 headings into 0 to 360 degrees sub ConvertHeadingToDegrees { my $Heading = $_[0]; my $ReverseHeading = 256 - $Heading; my $ConvertAngle = $ReverseHeading * 1.40625; if ($ConvertAngle <= 270) { $ConvertAngle = $ConvertAngle + 90; } else { $ConvertAngle = $ConvertAngle - 270; } return $ConvertAngle; } #Usage: plugin::Debug("Message", Color, Mob); # "Message" is a required field and is the message you want to show up in the debug # Color is an optional field and if not set will default to a pink/purple color # Mob is an optional field if you want to export a particular mob to debug from (used for getting the name) # Example 1: plugin::Debug("Event Started", 7); # Example 2: plugin::Debug("Event Started"); sub Debug { my $npc = plugin::val('$npc'); my $client = plugin::val('$client'); my $MyMessage = $_[0]; my $TextColor = $_[1]; if (!$TextColor) { $TextColor = 326; #Set the Text Color for the Message (this one is bright purple) } my $Mob = $_[2]; if (!$Mob) { if ($npc) { # NPC Quest $Mob = $npc; } elsif ($client) { # Player Quest $Mob = $client; } } my $MobName = "NO_NAME"; if ($Mob) { #Get the clean name of the Mob sending the message $MobName = $Mob->GetCleanName(); } #Send a message in purple (default) to GMs in the Zone only quest::gmsay("$MobName Debugs: $MyMessage", $TextColor); } return 1; #This line is required at the end of every plugin file in order to use it
Source: 17 Jan 2022
Quest Source: 28 May 2022