| trevius | 
			06-25-2013 05:04 AM | 
		 
		 
		 
		
		
		
	Quote: 
	
	
		
			 
			
				
					Originally Posted by KLS
					(Post 221979)
				 
				One thing that may throw a wrench in this is loottables are in shared memory which (generally) requires a server reboot to reload. 
			
			 
		 | 
	 
	 
 On Storm Haven, we started doing most loot via scripts.  You can add loot on the fly anytime via scripts and using the default.pl makes it really easy to split up loot to an entire zone with a high amount of flexibility.  For example, I have most of my newer leveling content using a scaling loot system that works via a plugin I made.  It scales the number of drops based on how big the group is that first engages the NPC.  I think this helps to promote grouping a bit more, because people don't have to worry about needing to kill 6X the amount of whatever mobs to get all of their quest drops for an entire group.  So, you can group up to level up quicker without being bottle-necked by waiting for specific drops as much.
 
We have quite a few plugins created for adding loot in different ways, but here are a couple of examples for adding cash and scaling drops to a group:
 
	Code: 
	
 ###Usage: plugin::AddRandomCash(MinCash, MaxCash, [ AllowRepeatAdds, NPC ]); 
# Adds a random amount of cash to the NPC based on the MinCash and MaxCash settings. 
# All rewards are based on Copper amounts (1000 = 1 plat) 
# AllowRepeatAdds will allow money to be added to the same NPC more than once if set to 1, or will block extra adds if left off (0) 
# NPC is an optional field for setting a specific NPC to add cash to 
 
sub AddRandomCash { 
 
        my $npc = plugin::val('$npc'); 
        my $MinCash = $_[0]; 
        my $MaxCash = $_[1]; 
        my $AllowRepeatAdds = $_[2]; 
        my $SpecificNPC = $_[3]; 
         
        if ($SpecificNPC) 
        { 
                $npc = $SpecificNPC; 
        } 
 
        if (!$npc->EntityVariableExists(957) || $AllowRepeatAdds) 
        {         
                $npc->SetEntityVariable(957, 1); 
                my $CashReward = plugin::RandomRange($MinCash, $MaxCash); 
 
                my $Plat = int($CashReward / 1000); 
                my $Gold = int(($CashReward - ($Plat * 1000)) / 100); 
                my $Silv = int(($CashReward - (($Plat * 1000) + ($Gold * 100))) / 10); 
                my $Copp = $CashReward - (($Plat * 1000) + ($Gold * 100) + ($Silv * 10)); 
                #plugin::Debug("Random Cash: $CashReward, Plat $Plat, Gold $Gold, Silv $Silv, Copp $Copp"); 
                 
                $npc->AddCash($Copp, $Silv, $Gold, $Plat); 
                return $CashReward; 
        } 
        return 0; 
} 
 
 
###Usage: plugin::ScaleDropToGroup(item_id, Chance[1-100], Scale[1-100]=100, Group_Only=0, Max_Chance=100, Trivial=0); 
# Drops an item X amount of times depending on how many clients are in the group. 
# Chance is the overall chance for the item to drop 
# Scale is the rate that the drop chance decreases to for each additional member (Diminishing return) 
# Group_Only is an optional setting.  If 0, solo players will have a chance for this to drop.  If 1, only groups will have a chance for the drop. 
# The Group Only option is primarily for adding an item that already exists in the NPC's loot table. 
# Max_Chance option allows the chance range to be increased above the default 100. 
# Setting Max_Chance to 1000 will make the chance roll from 1 to 1000 instead of 1 to 100 which allows drop rates less than 1%. 
# Trivial can enable the trivial loot checks to restrict scaling drops to only groups who can earn experience from the kill (default is disabled 0). 
# Example 1: plugin::ScaleDropToGroup(1001, 100, 80); 
# This example gives the item a 100% chance to be added, but each additional member reduces that chance to 80% of the previous chance 
# Example 2: plugin::ScaleDropToGroup(1001, 5, 80, 1); 
# This example gives the item a 5% chance to be added, but each additional member reduces that chance to 80% of the previous chance 
# Example 2 will not add the item if an ungrouped client is fighting the NPC. 
# Example 3: plugin::ScaleDropToGroup(1001, 1, 100, 0, 500, 1); 
# This example will give the item a 0.1% drop chance for each member in the group or for solo players, but only scales to the group if they can get exp from the kill 
 
sub ScaleDropToGroup { 
        my $npc = plugin::val('$npc'); 
        my $client = plugin::val('$client'); 
        my $userid = plugin::val('$userid'); 
        my $entity_list = plugin::val('$entity_list'); 
        my $item_id = $_[0]; 
        my $drop_chance = $_[1];        # Chance 
        my $per_member_chance = $_[2];        # Scale 
        my $group_only = $_[3]; 
        my $max_chance = $_[4]; 
        my $trivial = $_[5]; 
 
        # If the event was triggered by a pet, get the pet's owner as the client 
        my $Attacker = $entity_list->GetMobByID($userid); 
        my $Owner = 0; 
        my $PetOwnerID = 0; 
        my $SwarmOwnerID = 0; 
        if ($Attacker && $Attacker->IsNPC()) 
        { 
                $PetOwnerID = $Attacker->CastToNPC()->GetOwnerID(); 
                $SwarmOwnerID = $Attacker->CastToNPC()->GetSwarmOwner(); 
        } 
        if ($PetOwnerID) 
        { 
                $Owner = $entity_list->GetClientByID($PetOwnerID); 
        } 
        if ($SwarmOwnerID) 
        { 
                $Owner = $entity_list->GetClientByID($SwarmOwnerID); 
        } 
        if ($Owner) 
        { 
                $client = $Owner; 
        } 
 
        if (!$max_chance) { $max_chance = 100; } 
        if ($drop_chance > $max_chance) { $drop_chance = $max_chance; } 
        if (!$per_member_chance) { $per_member_chance = 100; } 
 
        my $Charge = 0;         
        my $Stack_Size = $npc->GetItemStat($item_id, "stacksize");  
        my $Has_Charge = $npc->GetItemStat($item_id, "maxcharges");  
        if ($Stack_Size >= 1) { $Charge = 1; } 
        if ($Has_Charge >= 1) { $Charge = $Has_Charge; } 
 
        #plugin::Debug("Starting Plugin"); 
        # Verify all of the required fields are set properly 
        if ($drop_chance > 0 && $item_id) 
        { 
                if($client)        # Verify we got a client 
                { 
                        my $ClientGroup = $client->GetGroup();        # Check if the client is in a group 
                        if ($ClientGroup) 
                        { 
                                #plugin::Debug("Got Group"); 
                                my $GroupCount = $ClientGroup->GroupCount();        # Count the group members 
                                my $NPCLevel = $npc->GetLevel(); 
                                my $HighLevel = $ClientGroup->GetHighestLevel(); 
                                my $ExpMaxLevel = (($NPCLevel / 3) * 4); 
                                #plugin::Debug("Highest Level is $HighLevel - NPC Max Exp Level is $ExpMaxLevel"); 
                                if (!$trivial || $HighLevel <= $ExpMaxLevel) 
                                { 
                                        if ($GroupCount > 1) 
                                        { 
                                                # Create the variable that tracks the highest number of opponents this NPC has had since it spawned 
                                                if (!$npc->EntityVariableExists($item_id)) 
                                                {         
                                                        $npc->SetEntityVariable($item_id, 1); 
                                                } 
                                                my $DropTotal = $npc->GetEntityVariable($item_id); 
                                                #plugin::Debug("Group Total $GroupCount, NPC Total $DropTotal"); 
                                                if ($GroupCount > $DropTotal) 
                                                { 
                                                        # Save the highest number of opponents 
                                                        $npc->SetEntityVariable($item_id, $GroupCount); 
                                                        my $scale_rate = 100; 
                                                        #plugin::Debug("Scale Rate $scale_rate"); 
                                                        # Run a loop to do the math and add loot 
                                                        my $StartCount = 1; 
                                                        if ($group_only) 
                                                        { 
                                                                $StartCount = 2; 
                                                        } 
                                                        for ($count = $StartCount; $count <= $GroupCount; $count++) 
                                                        { 
                                                                #plugin::Debug("Count $count"); 
                                                                $scale_rate = $scale_rate * $per_member_chance / 100; 
                                                                if ($count > $DropTotal) 
                                                                { 
                                                                        #plugin::Debug("Ready to roll to add the loot"); 
                                                                        my $ActualChance = $drop_chance * $scale_rate / $max_chance; 
                                                                        my $RandomNum = plugin::RandomRange(1, $max_chance); 
                                                                        #plugin::Debug("Actual Chance $ActualChance - Random Number $RandomNum"); 
                                                                        if ($ActualChance >= $RandomNum) 
                                                                        { 
                                                                                #plugin::Debug("Dropping $loottable with an actual chance of $ActualChance and group count of $GroupCount"); 
                                                                                $npc->AddItem($item_id, $Charge, 0); 
                                                                                #plugin::Debug("Group Drop Added"); 
                                                                        } 
                                                                } 
                                                        } 
                                                } 
                                        } 
                                } 
                        } 
                        else        # No Group 
                        { 
                                if (!$group_only) 
                                { 
                                        # Create the variable that tracks that this has been rolled for once already 
                                        if (!$npc->EntityVariableExists($item_id)) 
                                        {         
                                                $npc->SetEntityVariable($item_id, 1); 
                                                my $RandomNum = plugin::RandomRange(1, $max_chance); 
                                                if ($drop_chance >= $RandomNum) 
                                                { 
                                                        $npc->AddItem($item_id, $Charge, 0); 
                                                        #plugin::Debug("Solo Drop Added"); 
                                                } 
                                        } 
                                } 
                        } 
                } 
                else        # No Client Attacking 
                { 
                        if (!$group_only) 
                        { 
                                # Create the variable that tracks that this has been rolled for once already 
                                if (!$npc->EntityVariableExists($item_id)) 
                                {         
                                        $npc->SetEntityVariable($item_id, 1); 
                                        my $RandomNum = plugin::RandomRange(1, $max_chance); 
                                        if ($drop_chance >= $RandomNum) 
                                        { 
                                                $npc->AddItem($item_id, $Charge, 0); 
                                                #plugin::Debug("Solo Drop Added"); 
                                        } 
                                } 
                        } 
                } 
        } 
} 
 Side Note: You might notice there are a lot of lines using plugin::Debug(), and that is one that I don't think is available in the standard quests repository.  All of the examples above are commented out, so this is not required, but I find it pretty useful.  It is nice because you can use it to debug your scripts to see what is happening (or what is failing) and only GMs will see it.  This way, if you leave a debug message in place, you don't have to worry about players ever seeing it (vs if you used shout or say for debugs previously).
 
	Code: 
	
 #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);         
} 
 
Here is an example that makes use of those plugins in a default.pl file from one of our zones.  Note that it uses EVENT_COMBAT to do the loot, which is so it can determine how to scale the loot drops based on how many members are in the group (if any).  This example is fairly complex, but works pretty well in scenarios where you don't need an overly complex loot table for a zone.  Using something like this, you could make a custom zone full of loot in no time:
 
	Code: 
	
 sub EVENT_COMBAT { 
 
        # Prevent pets or charmed NPCs from loading the default.pl 
        if (!$npc || $npc->GetOwnerID() || $npc->GetSwarmOwner()) 
        { 
                return; 
        } 
 
        if($combat_state) 
        { 
                my $NPCRace = $npc->GetRace(); 
                my $NPCName = $npc->GetName(); 
 
 
                # Array for Loot Drop Selection 
                my @LootList = ( 
                        39235,        # Sash of Divine Retribution Armor  ID: 39235 
                        39218,        # Dragonskull of Relic Armor  ID: 39218 
                        39221        # Sash of Seven Scales Armor  ID: 39221 
                ); 
                my @ArmorLootList = ( 
                        39220,        # Dragontamer Sleeves Armor  ID: 39220 
                        46795,        # Windcaller's War Gear Armor  ID: 46795 
                        46796,        # Windcaller's Under Armor Armor  ID: 46796 
                        39216,        # Hollowed Dragon Tusk Armor  ID: 39216 
                        39217,        # Stretched Dragonback Bracer Armor  ID: 39217 
                        39219,        # Dragonrider Chain Gloves Armor  ID: 39219 
                        39223,        # Silken Boots of the Magus Armor  ID: 39223 
                        46797,        # Ringmail Ritual Boots Armor  ID: 46797 
                        46798        # Plaguehide Boots Armor  ID: 46798 
                ); 
 
                my $ListLen = @LootList; 
                my $ArmorListLen = @ArmorLootList; 
                my $SelectLoot = $LootList[plugin::RandomRange(0, $ListLen)]; 
                my $SelectArmorLoot = $ArmorLootList[plugin::RandomRange(0, $ArmorListLen)]; 
                #Usage: plugin::ScaleDropToGroup(item_id, chance[1-100], scale[1-100]=100, group_only=0, max_chance=100); 
                plugin::ScaleDropToGroup($SelectLoot, 5, 100); 
                plugin::ScaleDropToGroup($SelectArmorLoot , 7, 100); 
                plugin::ScaleDropToGroup(79980, 20, 20);        # Urn of Rejuvenation - Single Charge clicky (should help soloing) 
                 
                # Array for Aug Loot Drop Selection 
                my @AugLootList = ( 
                        39236,        # Shadowed Stone of Hidden Flame Aug: 8   ID: 39236 
                        46744,        # Ash of the Fallen Aug: 8   ID: 46744 
                        39333        # Smoldered Gem of Battle Aug: 8   ID: 39333 
                ); 
                my $AugListLen = @AugLootList; 
                my $SelectAugLoot = $AugLootList[plugin::RandomRange(0, $AugListLen)]; 
                # Adjust Drop Rate 
                my $AugDropRate = 3; 
                my $AugScaleRate = 100; 
                my $SmallExpDropRate = 2; 
                my $SmallExpScaleRate = 100; 
                my $LargeExpDropRate = 1; 
                my $LargeExpScaleRate = 100; 
                if ($NPCName =~ /^#/ && $NPCName !~ /^##/) 
                { 
                        #plugin::Debug("Increasing Drop Rates for Augs and Exp Shards (Named)"); 
                        # Named/Rare NPC 
                        $AugDropRate = 25; 
                        $AugScaleRate = 20; 
                        $SmallExpDropRate = 20; 
                        $SmallExpScaleRate = 20; 
                        $LargeExpDropRate = 10; 
                        $LargeExpScaleRate = 20; 
                } 
                plugin::ScaleDropToGroup($SelectAugLoot, $AugDropRate, $AugScaleRate); 
                plugin::ScaleDropToGroup(8479, $SmallExpDropRate, $SmallExpScaleRate);        # 8479 - Small Shard of Experience - Spell: Special Effect - 9999 - ScriptFileID 12345 
                plugin::ScaleDropToGroup(8484, $LargeExpDropRate, $LargeExpScaleRate);        # 8484 - Large Shard of Experience - Spell: Special Effect - 9999 - ScriptFileID 12345 
                 
                # Set Cash Drops 
                if ($NPCName =~ /^#/ && $NPCName !~ /^##/) 
                { 
                        # Named/Rare NPC 
                        plugin::AddRandomCash(6500, 20000); 
                } 
                else 
                { 
                        # Trash Mobs 
                        plugin::AddRandomCash(3500, 10000); 
                } 
                 
                # Handle Specific Race or NPC stuff 
                 
                # Goblins 
                if ($NPCRace == $GoblinRace) 
                { 
                        if ($NPCName =~ /sunstone/i) 
                        { 
                                plugin::ScaleDropToGroup(8474, 6, 100);        # 8474 - Sunstone Pendant of Loyalty 
                                plugin::ScaleDropToGroup(8422, 6, 100);        # 8422 - Chewy Goblin Eye 
                        }                 
                        if ($NPCName =~ /tidewater/i) 
                        { 
                                plugin::ScaleDropToGroup(8478, 6, 100);        # 8478 - Tidewater Pendant of Loyalty 
                                plugin::ScaleDropToGroup(8422, 6, 100);        # 8422 - Chewy Goblin Eye 
                                plugin::ScaleDropToGroup(8473, 7, 75);        # 8473 - Tidewater Conch Shell 
                        } 
                        plugin::ScaleDropToGroup(8740, 6, 25);        # 8740 - Goblin Bone Shaft - Drops from Goblins in Suncrest Isle 
                } 
 
                # All Animals 
                if ($NPCRace == $RaptorRace || $NPCRace == $DrakeRace || $NPCRace == $BasiliskRace || $NPCRace == $TigerRace) 
                { 
                        plugin::ScaleDropToGroup(8423, 6, 100);        # 8423 - Tough Animal Heart 
                } 
        } 
 
} 
  
	 |