using System;
using System.Collections.Generic;
using log4net;
using ACE.Database;
using ACE.Entity;
using ACE.Entity.Enum;
using ACE.Entity.Enum.Properties;
using ACE.Entity.Models;
using ACE.Server.Entity;
using ACE.Server.Entity.Actions;
using ACE.Server.Factories;
using ACE.Server.Managers;
using ACE.Server.Network.GameMessages.Messages;
namespace ACE.Server.WorldObjects
{
///
/// Pet Devices are the essences used to summon creatures
///
public class PetDevice : WorldObject
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public int? PetClass
{
get => GetProperty(PropertyInt.PetClass);
set { if (value.HasValue) SetProperty(PropertyInt.PetClass, value.Value); else RemoveProperty(PropertyInt.PetClass); }
}
public uint? Pet
{
get => GetProperty(PropertyInstanceId.Pet);
set { if (value.HasValue) SetProperty(PropertyInstanceId.Pet, value.Value); else RemoveProperty(PropertyInstanceId.Pet); }
}
///
/// A new biota be created taking all of its values from weenie.
///
public PetDevice(Weenie weenie, ObjectGuid guid) : base(weenie, guid)
{
SetEphemeralValues();
// todo: remove me when the data is fixed
Structure = MaxStructure;
}
///
/// Restore a WorldObject from the database.
///
public PetDevice(Biota biota) : base(biota)
{
SetEphemeralValues();
}
private void SetEphemeralValues()
{
}
public override void ActOnUse(WorldObject activator)
{
if (!(activator is Player player))
return;
// Good PCAP example of using a PetDevice to summon a pet:
// Asherons-Call-packets-includes-3-towers\pkt_2017-1-30_1485823896_log.pcap lines 27837 - 27843
if (PetClass == null)
{
log.Error($"{activator.Name}.ActOnUse({Name}) - PetClass is null for PetDevice {WeenieClassId}");
return;
}
if (Structure == 0)
{
//player.Session.Network.EnqueueSend(new GameEventCommunicationTransientString(player.Session, "You must refill the essence to use it again."));
player.Session.Network.EnqueueSend(new GameMessageSystemChat("Your summoning device does not have enough charges to function!", ChatMessageType.Broadcast));
return;
}
var wcid = (uint)PetClass;
var result = SummonCreature(player, wcid);
if (result == null || result.Value)
{
// CombatPet devices should always have structure
if (Structure != null)
{
// decrease remaining uses
Structure--;
player.Session.Network.EnqueueSend(new GameMessagePublicUpdatePropertyInt(this, PropertyInt.Structure, Structure.Value));
}
}
else
{
// this would be a good place to send a friendly reminder to install the latest summoning updates from ACE-World-Patch
}
}
public override ActivationResult CheckUseRequirements(WorldObject activator)
{
if (!(activator is Player player))
return new ActivationResult(false);
var baseRequirements = base.CheckUseRequirements(activator);
if (!baseRequirements.Success)
return baseRequirements;
// verify summoning mastery
if (SummoningMastery != null && player.SummoningMastery != SummoningMastery)
{
player.Session.Network.EnqueueSend(new GameMessageSystemChat($"You must be a {SummoningMastery} to use the {Name}", ChatMessageType.Broadcast));
return new ActivationResult(false);
}
// duplicating some of this verification logic here from Pet.Init()
// since the PetDevice owner and the summoned Pet are separate objects w/ potentially different heartbeat offsets,
// the cooldown can still expire before the CombatPet's lifespan
// in this case, if the player tries to re-activate the PetDevice while the CombatPet is still in the world,
// we want to return an error without re-activating the cooldown
if (player.CurrentActivePet != null && player.CurrentActivePet is CombatPet)
{
if (PropertyManager.GetBool("pet_stow_replace").Item)
{
// original ace
player.SendTransientError($"{player.CurrentActivePet.Name} is already active");
return new ActivationResult(false);
}
else
{
// retail stow
var weenie = DatabaseManager.World.GetCachedWeenie((uint)PetClass);
if (weenie == null || weenie.WeenieType != WeenieType.Pet)
{
player.SendTransientError($"{player.CurrentActivePet.Name} is already active");
return new ActivationResult(false);
}
}
}
return new ActivationResult(true);
}
public bool? SummonCreature(Player player, uint wcid)
{
var wo = WorldObjectFactory.CreateNewWorldObject(wcid);
if (wo == null)
{
log.Error($"{player.Name}.SummonCreature({wcid}) - couldn't find wcid for PetDevice {WeenieClassId} - {WeenieClassName}");
return false;
}
var pet = wo as Pet;
if (pet == null)
{
log.Error($"{player.Name}.SummonCreature({wcid}) - PetDevice {WeenieClassId} - {WeenieClassName} tried to summon {wo.WeenieClassId} - {wo.WeenieClassName} of unknown type {wo.WeenieType}");
return false;
}
var success = pet.Init(player, this);
if (success != true) wo.Destroy();
return success;
}
///
/// Maps an Essence to a WCID to be spawned
///
public static Dictionary> PetDeviceToPetMapping = new Dictionary>()
{
// ============================ Geomancer ============================
// ============ Golems ============
{ 48886, new Tuple(48887, DamageType.Bludgeon) }, // mud golem (15)
{ 48890, new Tuple(48891, DamageType.Bludgeon) }, // sandstone golem (30)
{ 48878, new Tuple(48879, DamageType.Bludgeon) }, // copper golem (50)
{ 48888, new Tuple(48889, DamageType.Bludgeon) }, // oak golem (80)
{ 48882, new Tuple(48883, DamageType.Bludgeon) }, // gold golem (100)
{ 48880, new Tuple(48881, DamageType.Bludgeon) }, // coral golem (125)
{ 48884, new Tuple(48885, DamageType.Bludgeon) }, // iron golem (150)
// ============================ Naturalist ============================
// ============ Grievvers ============
{ 49366, new Tuple(49052, DamageType.Acid) }, // acid grievver (50)
{ 49367, new Tuple(49053, DamageType.Acid) }, // acid grievver (80)
{ 49368, new Tuple(49054, DamageType.Acid) }, // acid grievver (100)
{ 49369, new Tuple(49055, DamageType.Acid) }, // acid grievver (125)
{ 49370, new Tuple(49056, DamageType.Acid) }, // acid grievver (150)
{ 49371, new Tuple(49057, DamageType.Acid) }, // acid grievver (180)
{ 49372, new Tuple(49058, DamageType.Acid) }, // caustic grievver (200)
{ 49380, new Tuple(49066, DamageType.Fire) }, // fire grievver (50)
{ 49381, new Tuple(49067, DamageType.Fire) }, // fire grievver (80)
{ 49382, new Tuple(49068, DamageType.Fire) }, // fire grievver (100)
{ 49383, new Tuple(49069, DamageType.Fire) }, // fire grievver (125)
{ 49384, new Tuple(49070, DamageType.Fire) }, // fire grievver (150)
{ 49385, new Tuple(49071, DamageType.Fire) }, // fire grievver (180)
{ 49386, new Tuple(49072, DamageType.Fire) }, // scorched grievver (200)
{ 49387, new Tuple(49073, DamageType.Cold) }, // frost grievver (50)
{ 49388, new Tuple(49074, DamageType.Cold) }, // frost grievver (80)
{ 49389, new Tuple(49075, DamageType.Cold) }, // frost grievver (100)
{ 49390, new Tuple(49076, DamageType.Cold) }, // frost grievver (125)
{ 49391, new Tuple(49077, DamageType.Cold) }, // frost grievver (150)
{ 49392, new Tuple(49078, DamageType.Cold) }, // frost grievver (180)
{ 49365, new Tuple(49051, DamageType.Cold) }, // arctic grievver (200)
//{ -1, -1 }, // glacial grievver (200) ?
{ 49373, new Tuple(49059, DamageType.Electric) }, // lightning grievver (50)
{ 49374, new Tuple(49060, DamageType.Electric) }, // lightning grievver (80)
{ 49375, new Tuple(49061, DamageType.Electric) }, // lightning grievver (100)
{ 49376, new Tuple(49062, DamageType.Electric) }, // lightning grievver (125)
{ 49377, new Tuple(49063, DamageType.Electric) }, // lightning grievver (150)
{ 49378, new Tuple(49064, DamageType.Electric) }, // lightning grievver (180)
{ 49379, new Tuple(49065, DamageType.Electric) }, // excited grievver (200)
// ============ Moars ============
{ 49338, new Tuple(49108, DamageType.Acid) }, // acid moar (50)
{ 49339, new Tuple(49109, DamageType.Acid) }, // acid moar (80)
{ 49340, new Tuple(49110, DamageType.Acid) }, // acid moar (100)
{ 49341, new Tuple(49111, DamageType.Acid) }, // acid moar (125)
{ 49342, new Tuple(49112, DamageType.Acid) }, // acid moar (150)
{ 49343, new Tuple(49113, DamageType.Acid) }, // acid moar (180)
{ 49344, new Tuple(49114, DamageType.Acid) }, // blistering moar (200)
//{ 49344, 49114 }, // blistering moar (200)
{ 49352, new Tuple(49122, DamageType.Fire) }, // fire moar (50)
{ 49353, new Tuple(49123, DamageType.Fire) }, // fire moar (80)
{ 49354, new Tuple(49124, DamageType.Fire) }, // fire moar (100)
{ 49355, new Tuple(49125, DamageType.Fire) }, // fire moar (125)
{ 49356, new Tuple(49126, DamageType.Fire) }, // fire moar (150)
{ 49357, new Tuple(49127, DamageType.Fire) }, // fire moar (180)
{ 49358, new Tuple(49128, DamageType.Fire) }, // volcanic moar (200)
{ 49359, new Tuple(49129, DamageType.Cold) }, // frost moar (50)
{ 49360, new Tuple(49130, DamageType.Cold) }, // frost moar (80)
{ 49361, new Tuple(49131, DamageType.Cold) }, // frost moar (100)
{ 49362, new Tuple(49132, DamageType.Cold) }, // frost moar (125)
{ 49363, new Tuple(49133, DamageType.Cold) }, // frost moar (150)
{ 49364, new Tuple(49134, DamageType.Cold) }, // frost moar (180)
{ 49337, new Tuple(49107, DamageType.Cold) }, // freezing moar (200)
{ 49345, new Tuple(49115, DamageType.Electric) }, // lightning moar (50)
{ 49346, new Tuple(49116, DamageType.Electric) }, // lightning moar (80)
{ 49347, new Tuple(49117, DamageType.Electric) }, // lightning moar (100)
{ 49348, new Tuple(49118, DamageType.Electric) }, // lightning moar (125)
{ 49349, new Tuple(49119, DamageType.Electric) }, // lightning moar (150)
{ 49350, new Tuple(49120, DamageType.Electric) }, // lightning moar (180)
{ 49351, new Tuple(49121, DamageType.Electric) }, // electrified moar (200)
// ============ Phyntos Wasps ============
{ 49524, new Tuple(49136, DamageType.Acid) }, // acid phyntos wasp (50)
{ 49525, new Tuple(49137, DamageType.Acid) }, // acid phyntos wasp (80)
{ 49526, new Tuple(49138, DamageType.Acid) }, // acid phyntos wasp (100)
{ 49527, new Tuple(49139, DamageType.Acid) }, // acid phyntos wasp (125)
{ 49528, new Tuple(49140, DamageType.Acid) }, // acid phyntos wasp (150)
{ 49529, new Tuple(49141, DamageType.Acid) }, // acid phyntos wasp (180)
{ 49530, new Tuple(49142, DamageType.Acid) }, // acid phyntos swarm (200)
{ 49531, new Tuple(49143, DamageType.Fire) }, // fire phyntos wasp (50)
{ 49532, new Tuple(49144, DamageType.Fire) }, // fire phyntos wasp (80)
{ 49533, new Tuple(49145, DamageType.Fire) }, // fire phyntos wasp (100)
{ 49534, new Tuple(49146, DamageType.Fire) }, // fire phyntos wasp (125)
{ 49535, new Tuple(49147, DamageType.Fire) }, // fire phyntos wasp (150)
{ 49536, new Tuple(49148, DamageType.Fire) }, // fire phyntos wasp (180)
{ 49537, new Tuple(49149, DamageType.Fire) }, // fire phyntos swarm (200)
{ 49538, new Tuple(49150, DamageType.Cold) }, // frost phyntos wasp (50)
{ 49539, new Tuple(49151, DamageType.Cold) }, // frost phyntos wasp (80)
{ 49540, new Tuple(49152, DamageType.Cold) }, // frost phyntos wasp (100)
{ 49541, new Tuple(49153, DamageType.Cold) }, // frost phyntos wasp (125)
{ 49542, new Tuple(49154, DamageType.Cold) }, // frost phyntos wasp (150)
{ 49543, new Tuple(49155, DamageType.Cold) }, // frost phyntos wasp (180)
{ 49544, new Tuple(49156, DamageType.Cold) }, // frost phyntos swarm (200)
{ 49545, new Tuple(49157, DamageType.Electric) }, // lightning phyntos wasp (50)
{ 49546, new Tuple(49158, DamageType.Electric) }, // lightning phyntos wasp (80)
{ 49547, new Tuple(49159, DamageType.Electric) }, // lightning phyntos wasp (100)
{ 49548, new Tuple(49160, DamageType.Electric) }, // lightning phyntos wasp (125)
{ 49549, new Tuple(49161, DamageType.Electric) }, // lightning phyntos wasp (150)
{ 49550, new Tuple(49162, DamageType.Electric) }, // lightning phyntos wasp (180)
{ 49551, new Tuple(49135, DamageType.Electric) }, // lightning phyntos swarm (200)
// ============================ Necromancer ============================
// ============ Skeletons ============
{ 49213, new Tuple(49164, DamageType.Acid) }, // acid skeleton minion (50)
{ 49214, new Tuple(49165, DamageType.Acid) }, // acid skeleton minion (80)
{ 49215, new Tuple(49166, DamageType.Acid) }, // acid skeleton minion (100)
{ 49216, new Tuple(49167, DamageType.Acid) }, // acid skeleton bushi (125)
{ 49217, new Tuple(49168, DamageType.Acid) }, // acid skeleton bushi (150)
{ 49218, new Tuple(49169, DamageType.Acid) }, // acid skeleton bushi (180)
{ 49219, new Tuple(49163, DamageType.Acid) }, // acid skeleton samurai (200)
{ 48942, new Tuple(48943, DamageType.Fire) }, // fire skeleton minion (50)
{ 48944, new Tuple(48950, DamageType.Fire) }, // fire skeleton minion (80)
{ 48945, new Tuple(48951, DamageType.Fire) }, // fire skeleton minion (100)
{ 48946, new Tuple(48952, DamageType.Fire) }, // fire skeleton bushi (125)
{ 48947, new Tuple(48953, DamageType.Fire) }, // fire skeleton bushi (150)
{ 48948, new Tuple(48949, DamageType.Fire) }, // fire skeleton bushi (180)
{ 48956, new Tuple(48955, DamageType.Fire) }, // fire skeleton samurai (200)
{ 49227, new Tuple(49178, DamageType.Cold) }, // frost skeleton minion (50)
{ 49228, new Tuple(49179, DamageType.Cold) }, // frost skeleton minion (80)
{ 49229, new Tuple(49180, DamageType.Cold) }, // frost skeleton minion (100)
{ 49230, new Tuple(49181, DamageType.Cold) }, // frost skeleton bushi (125)
{ 49231, new Tuple(49182, DamageType.Cold) }, // frost skeleton bushi (150)
{ 49232, new Tuple(49183, DamageType.Cold) }, // frost skeleton bushi (180)
{ 49212, new Tuple(49177, DamageType.Cold) }, // frost skeleton samurai (200)
{ 49220, new Tuple(49171, DamageType.Electric) }, // lightning skeleton minion (50)
{ 49221, new Tuple(49172, DamageType.Electric) }, // lightning skeleton minion (80)
{ 49222, new Tuple(49173, DamageType.Electric) }, // lightning skeleton minion (100)
{ 49223, new Tuple(49174, DamageType.Electric) }, // lightning skeleton bushi (125)
{ 49224, new Tuple(49175, DamageType.Electric) }, // lightning skeleton bushi (150)
{ 49225, new Tuple(49176, DamageType.Electric) }, // lightning skeleton bushi (180)
{ 49226, new Tuple(49170, DamageType.Electric) }, // lightning skeleton samurai (200)
// ============ Spectres ============
{ 49421, new Tuple(49394, DamageType.Acid) }, // acid spectre (50)
{ 49422, new Tuple(49395, DamageType.Acid) }, // acid spectre (80)
{ 49423, new Tuple(49396, DamageType.Acid) }, // acid spectre (100)
{ 49424, new Tuple(49397, DamageType.Acid) }, // acid spectre (125)
{ 49425, new Tuple(49398, DamageType.Acid) }, // acid spectre (150)
{ 49426, new Tuple(49399, DamageType.Acid) }, // acid spectre (180)
{ 49427, new Tuple(49393, DamageType.Acid) }, // acid maiden (200)
{ 49435, new Tuple(49408, DamageType.Fire) }, // fire spectre (50)
{ 49436, new Tuple(49409, DamageType.Fire) }, // fire spectre (80)
{ 49437, new Tuple(49410, DamageType.Fire) }, // fire spectre (100)
{ 49438, new Tuple(49411, DamageType.Fire) }, // fire spectre (125)
{ 49439, new Tuple(49412, DamageType.Fire) }, // fire spectre (150)
{ 49440, new Tuple(49413, DamageType.Fire) }, // fire spectre (180)
{ 49441, new Tuple(49407, DamageType.Fire) }, // fire maiden (200)
{ 49442, new Tuple(49415, DamageType.Cold) }, // frost spectre (50)
{ 49443, new Tuple(49416, DamageType.Cold) }, // frost spectre (80)
{ 49444, new Tuple(49417, DamageType.Cold) }, // frost spectre (100)
{ 49445, new Tuple(49418, DamageType.Cold) }, // frost spectre (125)
{ 49446, new Tuple(49419, DamageType.Cold) }, // frost spectre (150)
{ 49447, new Tuple(49420, DamageType.Cold) }, // frost spectre (180)
{ 49448, new Tuple(49414, DamageType.Cold) }, // frost maiden (200)
{ 49428, new Tuple(49401, DamageType.Electric) }, // lightning spectre (50)
{ 49429, new Tuple(49402, DamageType.Electric) }, // lightning spectre (80)
{ 49430, new Tuple(49403, DamageType.Electric) }, // lightning spectre (100)
{ 49431, new Tuple(49404, DamageType.Electric) }, // lightning spectre (125)
{ 49432, new Tuple(49405, DamageType.Electric) }, // lightning spectre (150)
{ 49433, new Tuple(49406, DamageType.Electric) }, // lightning spectre (180)
{ 49434, new Tuple(49400, DamageType.Electric) }, // lightning maiden (200)
// ============ Zombies ============
{ 48972, new Tuple(49000, DamageType.Acid) }, // acid zombie (50)
{ 49234, new Tuple(49003, DamageType.Acid) }, // acid zombie (80)
{ 49235, new Tuple(49004, DamageType.Acid) }, // acid zombie (100)
{ 49236, new Tuple(49005, DamageType.Acid) }, // acid zombie (125)
{ 49237, new Tuple(49006, DamageType.Acid) }, // acid zombie (150)
{ 49238, new Tuple(49007, DamageType.Acid) }, // acid zombie (180)
{ 49239, new Tuple(49008, DamageType.Acid) }, // blistered zombie (200)
{ 49247, new Tuple(49016, DamageType.Fire) }, // fire zombie (50)
{ 49248, new Tuple(49017, DamageType.Fire) }, // fire zombie (80)
{ 49249, new Tuple(49018, DamageType.Fire) }, // fire zombie (100)
{ 49250, new Tuple(49019, DamageType.Fire) }, // fire zombie (125)
{ 49251, new Tuple(49020, DamageType.Fire) }, // fire zombie (150)
{ 49252, new Tuple(49021, DamageType.Fire) }, // fire zombie (180)
{ 49253, new Tuple(49022, DamageType.Fire) }, // charred zombie (200)
{ 49254, new Tuple(49023, DamageType.Cold) }, // frost zombie (50)
{ 49255, new Tuple(49024, DamageType.Cold) }, // frost zombie (80)
{ 49256, new Tuple(49025, DamageType.Cold) }, // frost zombie (100)
{ 49257, new Tuple(49026, DamageType.Cold) }, // frost zombie (125)
{ 49258, new Tuple(49027, DamageType.Cold) }, // frost zombie (150)
{ 49259, new Tuple(49028, DamageType.Cold) }, // frost zombie (180)
{ 49233, new Tuple(49029, DamageType.Cold) }, // frigid zombie (200)
{ 49240, new Tuple(49009, DamageType.Electric) }, // lightning zombie (50)
{ 49241, new Tuple(49010, DamageType.Electric) }, // lightning zombie (80)
{ 49242, new Tuple(49011, DamageType.Electric) }, // lightning zombie (100)
{ 49243, new Tuple(49012, DamageType.Electric) }, // lightning zombie (125)
{ 49244, new Tuple(49013, DamageType.Electric) }, // lightning zombie (150)
{ 49245, new Tuple(49014, DamageType.Electric) }, // lightning zombie (180)
{ 49246, new Tuple(49015, DamageType.Electric) }, // shocked zombie (200)
// // ============================ Primalist ============================
// ============ Elementals ============
{ 49261, new Tuple(49031, DamageType.Acid) }, // acid elemental (50)
{ 49262, new Tuple(49032, DamageType.Acid) }, // acid elemental (80)
{ 49263, new Tuple(49033, DamageType.Acid) }, // acid elemental (100)
{ 49264, new Tuple(49034, DamageType.Acid) }, // acid child (125)
{ 49265, new Tuple(49035, DamageType.Acid) }, // acid child (150)
{ 49266, new Tuple(49036, DamageType.Acid) }, // acid child (180)
{ 49267, new Tuple(49030, DamageType.Acid) }, // caustic knight (200)
{ 48959, new Tuple(48960, DamageType.Fire) }, // fire elemental (50)
{ 48961, new Tuple(48962, DamageType.Fire) }, // fire elemental (80)
{ 48963, new Tuple(48964, DamageType.Fire) }, // fire elemental (100)
{ 48965, new Tuple(48966, DamageType.Fire) }, // fire child (125)
{ 48967, new Tuple(48968, DamageType.Fire) }, // fire child (150)
{ 48969, new Tuple(48970, DamageType.Fire) }, // fire child (180)
{ 48957, new Tuple(48958, DamageType.Fire) }, // incendiary knight (200)
//{ 0, new Tuple(0, DamageType.Fire) }, // scorched knight (200) ?
{ 49275, new Tuple(49045, DamageType.Cold) }, // frost elemental (50)
{ 49276, new Tuple(49046, DamageType.Cold) }, // frost elemental (80)
{ 49277, new Tuple(49047, DamageType.Cold) }, // frost elemental (100)
{ 49278, new Tuple(49048, DamageType.Cold) }, // frost child (125)
{ 49279, new Tuple(49049, DamageType.Cold) }, // frost child (150)
{ 49280, new Tuple(49050, DamageType.Cold) }, // frost child (180)
{ 49260, new Tuple(49044, DamageType.Cold) }, // glacial knight (200)
{ 49268, new Tuple(49038, DamageType.Electric) }, // lightning elemental (50)
{ 49269, new Tuple(49039, DamageType.Electric) }, // lightning elemental (80)
{ 49270, new Tuple(49040, DamageType.Electric) }, // lightning elemental (100)
{ 49271, new Tuple(49041, DamageType.Electric) }, // lightning child (125)
{ 49272, new Tuple(49042, DamageType.Electric) }, // lightning child (150)
{ 49273, new Tuple(49043, DamageType.Electric) }, // lightning child (180)
{ 49274, new Tuple(49037, DamageType.Electric) }, // galvanic knight (200)
// ============ K'naths ============
{ 49282, new Tuple(49080, DamageType.Acid) }, // acid k'nath (50)
{ 49283, new Tuple(49081, DamageType.Acid) }, // acid k'nath (80)
{ 49284, new Tuple(49082, DamageType.Acid) }, // acid k'nath (100)
{ 49285, new Tuple(49083, DamageType.Acid) }, // acid k'nath (125)
{ 49286, new Tuple(49084, DamageType.Acid) }, // acid k'nath (150)
{ 49287, new Tuple(49085, DamageType.Acid) }, // acid k'nath (180)
{ 49288, new Tuple(49086, DamageType.Acid) }, // k'nath y'nda (200)
{ 49296, new Tuple(49094, DamageType.Fire) }, // fire k'nath (50)
{ 49297, new Tuple(49095, DamageType.Fire) }, // fire k'nath (80)
{ 49298, new Tuple(49096, DamageType.Fire) }, // fire k'nath (100)
{ 49299, new Tuple(49097, DamageType.Fire) }, // fire k'nath (125)
{ 49300, new Tuple(49098, DamageType.Fire) }, // fire k'nath (150)
{ 49301, new Tuple(49099, DamageType.Fire) }, // fire k'nath (180)
{ 49302, new Tuple(49100, DamageType.Fire) }, // k'nath b'orret (200)
{ 49303, new Tuple(49101, DamageType.Cold) }, // frost k'nath (50)
{ 49304, new Tuple(49102, DamageType.Cold) }, // frost k'nath (80)
{ 49305, new Tuple(49103, DamageType.Cold) }, // frost k'nath (100)
{ 49306, new Tuple(49104, DamageType.Cold) }, // frost k'nath (125)
{ 49307, new Tuple(49105, DamageType.Cold) }, // frost k'nath (150)
{ 49308, new Tuple(49106, DamageType.Cold) }, // frost k'nath (180)
{ 49281, new Tuple(49079, DamageType.Cold) }, // k'nath r'ajed (200)
{ 49289, new Tuple(49087, DamageType.Electric) }, // lightning k'nath (50)
{ 49290, new Tuple(49088, DamageType.Electric) }, // lightning k'nath (80)
{ 49291, new Tuple(49089, DamageType.Electric) }, // lightning k'nath (100)
{ 49292, new Tuple(49090, DamageType.Electric) }, // lightning k'nath (125)
{ 49293, new Tuple(49091, DamageType.Electric) }, // lightning k'nath (150)
{ 49294, new Tuple(49092, DamageType.Electric) }, // lightning k'nath (180)
{ 49295, new Tuple(49093, DamageType.Electric) }, // k'nath t'soct (200)
// ============ Wisps ============
{ 49310, new Tuple(49185, DamageType.Acid) }, // acid wisp (50)
{ 49311, new Tuple(49186, DamageType.Acid) }, // acid wisp (80)
{ 49312, new Tuple(49187, DamageType.Acid) }, // acid wisp (100)
{ 49313, new Tuple(49188, DamageType.Acid) }, // acid wisp (125)
{ 49314, new Tuple(49189, DamageType.Acid) }, // acid wisp (150)
{ 49315, new Tuple(49190, DamageType.Acid) }, // acid wisp (180)
{ 49316, new Tuple(49191, DamageType.Acid) }, // corrosion wisp (200)
{ 49324, new Tuple(49199, DamageType.Fire) }, // fire wisp (50)
{ 49325, new Tuple(49200, DamageType.Fire) }, // fire wisp (80)
{ 49326, new Tuple(49201, DamageType.Fire) }, // fire wisp (100)
{ 49327, new Tuple(49202, DamageType.Fire) }, // fire wisp (125)
{ 49328, new Tuple(49203, DamageType.Fire) }, // fire wisp (150)
{ 49329, new Tuple(49204, DamageType.Fire) }, // fire wisp (180)
{ 49330, new Tuple(49205, DamageType.Fire) }, // incendiary wisp (200)
{ 49331, new Tuple(49206, DamageType.Cold) }, // frost wisp (50)
{ 49332, new Tuple(49207, DamageType.Cold) }, // frost wisp (80)
{ 49333, new Tuple(49208, DamageType.Cold) }, // frost wisp (100)
{ 49334, new Tuple(49209, DamageType.Cold) }, // frost wisp (125)
{ 49335, new Tuple(49210, DamageType.Cold) }, // frost wisp (150)
{ 49336, new Tuple(49211, DamageType.Cold) }, // frost wisp (180)
{ 49309, new Tuple