//Lord Vardison
//Version 2.0
//Revised And Reimagined... The Pure Evil of TWM2 Has Been Reborn, Now With Less Crashing xD
// Now with difficulty levels :P
//  1, Easy: Standard Vardison Battle
//    - Limited Mobs
//    - Attacks On Normal
//    - Has Timed Grab Kills
//  2, Normal: Tougher Vardison Battle
//    - Enhanced Mob Spawns
//    - Slightly Faster Attacks
//    - Phase 3 Insta-Kills
//    - Shadow Orb Mechanic: Deaths to phase 3 initiate Shadow Orb, which is a 20 second to kill all mechanic.
//  3, Hard: The True Experience
//    - Minions A Plenty
//    - Quick Attacks
//    - Phases 2 & 3 Insta-Kill
//    - Shadow Orb at Phase 2 & 3
//  4, WTF!?!?! Why God... Why....
//    - The Army Comith...
//    - Attacks Are So Rapid....
//    - All Phases Insta-Kill, Phase 3 does the spawn camp thingy :D
//    - Shadow Orb at all Phases
//    - Shadow Orb regenerates Vardison's HP

$TWM2::VardisonDifficulty = 1;
$TWM2::Vardison_DMsg[1] = "Lord Vardison Fight [EASY]: The Standard Battle... Work Togther and Be Victorious.";
$TWM2::Vardison_DMsg[2] = "Lord Vardison Fight [NORMAL]: Vardison Has Enhanced His Skills, Will you prove stronger?";
$TWM2::Vardison_DMsg[3] = "Lord Vardison Fight [HARD]: The True Vardison Experience... Only The True Will Be Victorious...";
$TWM2::Vardison_DMsg[4] = "Lord Vardison Fight [WTF]: All Prayers Will Be Accepted Before You Painfully Die... Over And Over And Over....";
//Difficulty Variables, Don't Touch
$TWM2::Vardison_OrbKillTime = 12500;
$TWM2::Vardison1_AttSpeed[1] = 20000;
$TWM2::Vardison1_AttSpeed[2] = 17500;
$TWM2::Vardison1_AttSpeed[3] = 13500;
$TWM2::Vardison1_AttSpeed[4] = 7500;
$TWM2::Vardison2_AttSpeed[1] = 20000;
$TWM2::Vardison2_AttSpeed[2] = 17500;
$TWM2::Vardison2_AttSpeed[3] = 12500;
$TWM2::Vardison2_AttSpeed[4] = 7000;
$TWM2::Vardison3_AttSpeed[1] = 17500;
$TWM2::Vardison3_AttSpeed[2] = 15000;
$TWM2::Vardison3_AttSpeed[3] = 11500;
$TWM2::Vardison3_AttSpeed[4] = 6500;
$TWM2::Vardison1_CanOrb[1] = false;
$TWM2::Vardison1_CanOrb[2] = false;
$TWM2::Vardison1_CanOrb[3] = false;
$TWM2::Vardison1_CanOrb[4] = true;
$TWM2::Vardison2_CanOrb[1] = false;
$TWM2::Vardison2_CanOrb[2] = false;
$TWM2::Vardison2_CanOrb[3] = true;
$TWM2::Vardison2_CanOrb[4] = true;
$TWM2::Vardison3_CanOrb[1] = false;
$TWM2::Vardison3_CanOrb[2] = true;
$TWM2::Vardison3_CanOrb[3] = true;
$TWM2::Vardison3_CanOrb[4] = true;
$TWM2::Vardison_OrbRegenHP[1] = false;
$TWM2::Vardison_OrbRegenHP[2] = false;
$TWM2::Vardison_OrbRegenHP[3] = false;
$TWM2::Vardison_OrbRegenHP[4] = true;
$TWM2::Vardison1_MaxMinions[1] = 5;
$TWM2::Vardison1_MaxMinions[2] = 10;
$TWM2::Vardison1_MaxMinions[3] = 12;
$TWM2::Vardison1_MaxMinions[4] = 15;
$TWM2::Vardison2_MaxMinions[1] = 7;
$TWM2::Vardison2_MaxMinions[2] = 9;
$TWM2::Vardison2_MaxMinions[3] = 12;
$TWM2::Vardison2_MaxMinions[4] = 15;
$TWM2::Vardison3_MaxMinions[1] = 10;
$TWM2::Vardison3_MaxMinions[2] = 13;
$TWM2::Vardison3_MaxMinions[3] = 17;
$TWM2::Vardison3_MaxMinions[4] = 25;
$TWM2::Vardison_MinionCooldown[1] = 20;
$TWM2::Vardison_MinionCooldown[2] = 17;
$TWM2::Vardison_MinionCooldown[3] = 15;
$TWM2::Vardison_MinionCooldown[4] = 10;

//Particles & Emitters
datablock ParticleData(SummoningPierParticle) {
   dragCoeffiecient     = 0.0;
   gravityCoefficient   = -0.1;
   inheritedVelFactor   = 0.1;

   lifetimeMS           = 1500;
   lifetimeVarianceMS   = 50;

   textureName          = "special/cloudflash";

   spinRandomMin = -10.0;
   spinRandomMax = 10.0;

   colors[0]     = "1 0.18 0.03 0.4";
   colors[1]     = "0 134 139 0.3";
   colors[2]     = "1 0.18 0.03 0.0";
   sizes[0]      = 10.0;
   sizes[1]      = 7.5;
   sizes[2]      = 5.0;
   times[0]      = 0.0;
   times[1]      = 0.6;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(SummoningPierEmitter) {
   ejectionPeriodMS = 3;
   periodVarianceMS = 0;

   ejectionOffset = 0.2;
   ejectionVelocity = 10.0;
   velocityVariance = 0.0;

   thetaMin         = 0.0;
   thetaMax         = 10.0;

   particles = "SummoningPierParticle";
};

datablock ParticleData(ShadowOrbParticle) {
   dragCoefficient      = 5;
   gravityCoefficient   = 0.0;
   inheritedVelFactor   = 0.0;
   constantAcceleration = -1.3;
   lifetimeMS           = 1000;
   lifetimeVarianceMS   = 150;
   textureName          = "special/cloudflash";
   useInvAlpha          =  false;
   colors[0]     = "0.5 0.1 0.9 1.0";
   colors[1]     = "0.5 0.1 0.9 1.0";
   colors[2]     = "0.5 0.1 0.9 1.0";
   sizes[0]      = 20.501;
   sizes[1]      = 25.001;
   sizes[2]      = 30.001;
   times[0]      = 0.0;
   times[1]      = 0.2;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(ShadowOrbEmitter) {
   ejectionPeriodMS = 15;
   periodVarianceMS = 5;

   ejectionVelocity = 42.7;  // A little oomph at the back end
   velocityVariance = 0.0;
   ejectionoffset = 0;
   thetaMin         = 0.0;
   thetaMax         = 180.0;
   phiReferenceVel = 0;
   phiVariance = "360";
   particles = "ShadowOrbParticle";
   overrideAdvances = true;
   orientParticles  = true;
};

datablock ParticleData(ShadowOrbDetonationParticle) {
   dragCoefficient      = 1.0;
   gravityCoefficient   = 0.00;
   windcoefficient      = 0.0;
   inheritedVelFactor   = 0.0;
   constantAcceleration = 10.0;
   lifetimeMS           = 1000;
   lifetimeVarianceMS   = 100;
   useInvAlpha          = true;
   spinRandomMin        = -90.0;
   spinRandomMax        = 90.0;
   textureName          = "special/cloudFlash";

   colors[0]     = "0.5 0.1 0.9 1.0";
   colors[1]     = "156 0 0 0.5";
   colors[2]     = "0.5 0.1 0.9 1.0";
   sizes[0]      = 500;
   sizes[1]      = 500;
   sizes[2]      = 2;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(ShadowOrbDetonationEmitter) {
   ejectionPeriodMS = 1;
   periodVarianceMS = 0;
   ejectionVelocity = 400.0;
   velocityVariance = 150.0;
   ejectionOffset   = 0.0;
   thetaMin         = 85;
   thetaMax         = 85;
   phiReferenceVel  = 0;
   phiVariance      = 360;
   overrideAdvances = false;
   particles = "ShadowOrbDetonationParticle";
};

datablock ParticleData(ShadowBaseParticle) {
   dragCoeffiecient     = 0.0;
   gravityCoefficient   = -0.2;
   inheritedVelFactor   = 0.0;

   lifetimeMS           = 800;
   lifetimeVarianceMS   = 500;

   useInvAlpha = false;
   spinRandomMin = -160.0;
   spinRandomMax = 160.0;

   animateTexture = true;
   framesPerSec = 15;

   textureName = "special/cloudflash";

   colors[0] = "0.5 0.1 0.9 1.0";
   colors[1] = "0.5 0.1 0.9 1.0";
   colors[2] = "0.5 0.1 0.9 1.0";

   sizes[0]      = 2.5;
   sizes[1]      = 2.7;
   sizes[2]      = 3.0;

   times[0]      = 0.0;
   times[1]      = 0.7;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(ShadowBaseEmitter) {
   ejectionPeriodMS = 10;
   periodVarianceMS = 0;

   ejectionVelocity = 1.5;
   velocityVariance = 0.3;

   thetaMin         = 0.0;
   thetaMax         = 30.0;

   particles = "ShadowBaseParticle";
};

//Projectile Datablocks:
//Ultimate Laser Projectile
datablock LinearFlareProjectileData(SuperlaserProjectile) {
   scale               = "15.0 15.0 15.0";
   faceViewer          = false;
   directDamage        = 1.0;
   hasDamageRadius     = true;
   indirectDamage      = 0.9;
   damageRadius        = 30.0;
   kickBackStrength    = 1000.0;
   radiusDamageType    = $DamageType::Explosion;

   explosion[0]           = "HyperDevCannonExplosion2";
   explosion[1]           = "SatchelMainExplosion";
   splash              = PlasmaSplash;
   baseEmitter         = HyperDevCannonBaseEmitter;


   dryVelocity       = 200.0;
   wetVelocity       = 200;
   velInheritFactor  = 0.5;
   fizzleTimeMS      = 10000;
   lifetimeMS        = 10000;
   explodeOnDeath    = false;
   reflectOnWaterImpactAngle = 0.0;
   explodeOnWaterImpact      = true;
   deflectionOnWaterImpact   = 0.0;
   fizzleUnderwaterMS        = -1;

   //activateDelayMS = 100;
   activateDelayMS = -1;

   size[0]           = 9;
   size[1]           = 10;
   size[2]           = 11;


   numFlares         = 400;
   flareColor        = "0.0 1.0 0";
   flareModTexture   = "flaremod";
   flareBaseTexture  = "flarebase";

   sound        = MissileProjectileSound;
   fireSound    = PlasmaFireSound;
   wetFireSound = PlasmaFireWetSound;

   hasLight    = true;
   lightRadius = 3.0;
   lightColor  = "0 0.75 0.25";

};

datablock LinearFlareProjectileData(ShadowBladeSlam) {
   scale               = "0.1 0.1 0.1";
   faceViewer          = false;
   directDamage        = 1.0;
   hasDamageRadius     = true;
   indirectDamage      = 5.0;
   damageRadius        = 15.0;
   kickBackStrength    = 1000.0;
   radiusDamageType    = $DamageType::BladeOfVengance;

   explosion[0]           = "SatchelMainExplosion";
   splash              = PlasmaSplash;


   dryVelocity       = 200.0;
   wetVelocity       = 200;
   velInheritFactor  = 0.5;
   fizzleTimeMS      = 10000;
   lifetimeMS        = 10000;
   explodeOnDeath    = false;
   reflectOnWaterImpactAngle = 0.0;
   explodeOnWaterImpact      = true;
   deflectionOnWaterImpact   = 0.0;
   fizzleUnderwaterMS        = -1;

   //activateDelayMS = 100;
   activateDelayMS = -1;

   size[0]           = "0.1";
   size[1]           = "0.1";
   size[2]           = "0.1";


   numFlares         = 1;
   flareColor        = "0.0 1.0 0";
   flareModTexture   = "flaremod";
   flareBaseTexture  = "flarebase";

   sound        = MissileProjectileSound;
   fireSound    = PlasmaFireSound;
   wetFireSound = PlasmaFireWetSound;

   hasLight    = true;
   lightRadius = 3.0;
   lightColor  = "0 0.75 0.25";

};

datablock LinearFlareProjectileData(ShadowBlastBolt) {
   projectileShapeName = "turret_muzzlepoint.dts";
   scale               = "1.0 1.0 1.0";
   faceViewer          = true;
   directDamage        = 0.9;
   hasDamageRadius     = true;
   indirectDamage      = 0.9;
   damageRadius        = 15.0;
   kickBackStrength    = 0.0;
   radiusDamageType    = $DamageType::Vardison;

   explosion           = "MortarExplosion";
   splash              = PlasmaSplash;

   baseEmitter        = ShadowBaseEmitter;

   dryVelocity       = 50.0; // z0dd - ZOD, 7/20/02. Faster plasma projectile. was 55
   wetVelocity       = -1;
   velInheritFactor  = 0.3;
   fizzleTimeMS      = 29500;
   lifetimeMS        = 30000;
   explodeOnDeath    = false;
   reflectOnWaterImpactAngle = 0.0;
   explodeOnWaterImpact      = true;
   deflectionOnWaterImpact   = 0.0;
   fizzleUnderwaterMS        = -1;

   //activateDelayMS = 100;
   activateDelayMS = -1;

   size[0]           = 0.2;
   size[1]           = 0.5;
   size[2]           = 0.1;


   numFlares         = 35;
   flareColor        = "1 0.18 0.03";
   flareModTexture   = "flaremod";
   flareBaseTexture  = "flarebase";

	sound        = PlasmaProjectileSound;
   fireSound    = FlamethrowerFireSound;
   wetFireSound = PlasmaFireWetSound;

   hasLight    = true;
   lightRadius = 10.0;
   lightColor  = "0.94 0.03 0.12";
};

//Armor Datablocks
datablock StaticShapeData(InitialVaridionHoloArmor) : StaticShapeDamageProfile {
	className = "player";
	shapeFile = "TR2Heavy_male.dts"; // dmiscf.dts, alternate
    mass = 1;
	elasticity = 0.1;
	friction = 0.9;
	collideable = 0;
    isInvincible = true;
};
function InitialVaridionHoloArmor::shouldApplyImpulse(%targetObject) {
   return false;
}

datablock PlayerData(VardisonStageOneArmor) : LightMaleHumanArmor {
   boundingBox = "1.63 1.63 2.6";
   maxDamage = 300.0;
   minImpactSpeed = 35;
   shapeFile = "medium_male.dts";

   debrisShapeName = "bio_player_debris.dts";

   //Foot Prints
   decalData   = HeavyBiodermFootprint;
   decalOffset = 0.4;

   waterBreathSound = WaterBreathBiodermSound;

   damageScale[$DamageType::W1700] = 3.0;
   damageScale[$DamageType::Bullet] = 0.10;  //I deny you shrike n0bs
   damageScale[$DamageType::BladeOfVengance] = 0.001;
};

datablock PlayerData(VardisonStageTwoArmor) : LightMaleHumanArmor {
   shapefile = "TR2medium_male.dts";
   mass = 500;
   maxDamage = 350.0;
   minImpactSpeed = 50;
   speedDamageScale = 0.015;
   boundingBox = "2.9 2.9 4.8";

   underwaterJetForce = 10;

   LFootSoftSound       = ZLordFootSound;
   RFootSoftSound       = ZLordFootSound;
   LFootHardSound       = HZLordFootSound;
   RFootHardSound       = HZLordFootSound;
   LFootMetalSound      = ZLordFootSound;
   RFootMetalSound      = ZLordFootSound;
   LFootSnowSound       = ZLordFootSound;
   RFootSnowSound       = ZLordFootSound;

   damageScale[$DamageType::M1700] = 1.5;
   damageScale[$DamageType::BladeOfVengance] = 0.001;

	max[RepairKit]			= 0;
	max[Mine]			= 0;
	max[Grenade]			= 0;
};

datablock PlayerData(VardisonStageThreeArmor) : LightMaleHumanArmor {
   shapefile = "TR2Heavy_male.dts";
   mass = 500;
   maxDamage = 500.0;
   minImpactSpeed = 50;
   speedDamageScale = 0.015;
   boundingBox = "2.9 2.9 4.8";

   underwaterJetForce = 10;

   LFootSoftSound       = ZLordFootSound;
   RFootSoftSound       = ZLordFootSound;
   LFootHardSound       = HZLordFootSound;
   RFootHardSound       = HZLordFootSound;
   LFootMetalSound      = ZLordFootSound;
   RFootMetalSound      = ZLordFootSound;
   LFootSnowSound       = ZLordFootSound;
   RFootSnowSound       = ZLordFootSound;

   damageScale[$DamageType::M1700] = 1.5;
   damageScale[$DamageType::BladeOfVengance] = 0.001;

	max[RepairKit]			= 0;
	max[Mine]			= 0;
	max[Grenade]			= 0;
};

datablock StaticShapeData(ShadowOrb) : StaticShapeDamageProfile {
	className = "Generator";
	shapeFile = "station_generator_large.dts";

	maxDamage      = 2.0;
	destroyedLevel = 2.0;
	disabledLevel  = 0.3;

	isShielded = false;
	energyPerDamagePoint = 240;
	maxEnergy = 50;
	rechargeRate = 0.25;

	explosion      = HandGrenadeExplosion;
	expDmgRadius = 1.0;
	expDamage = 0.05;
	expImpulse = 200;
 
    boundingBox = "5.0 5.0 5.0";
	dynamicType = $TypeMasks::StaticShapeObjectType;
	deployedObject = true;
	cmdCategory = "DSupport";
	cmdIcon = CMDSensorIcon;
	cmdMiniIconName = "commander/MiniIcons/com_deploymotionsensor";
	targetNameTag = 'Shadow Rift';
	deployAmbientThread = true;
	debrisShapeName = "debris_generic_small.dts";
	debris = DeployableDebris;
	heatSignature = 0;
	needsPower = true;
};

function ShadowOrb::onDestroyed(%this, %obj, %prevState) {
   if (%obj.isRemoved) {
      return;
   }
   if(isObject(%obj.waypoint)) {
      %obj.waypoint.schedule(500, "delete");
   }
   if(isObject($TWM2::VardisonManager.OrbSFX)) {
      $TWM2::VardisonManager.OrbSFX.schedule(500, "delete");
   }
   %obj.isRemoved = true;
   Parent::onDestroyed(%this, %obj, %prevState);
   %obj.schedule(500, "delete");
   $TWM2::VardisonManager.orbDestroyed();
}

//Boss Functions
function CheckVardisonManager() {
   if($TWM2::VardisonDifficulty < 1 || $TWM2::VardisonDifficulty > 4) {
      //Are the odds in your favor now, or will Vardison rek you endlessly?
      $TWM2::VardisonDifficulty = getRandom(1, 4);
   }
   if(!isObject($TWM2::VardisonManager)) {
      $TWM2::VardisonManager = new ScriptObject() {
         class = "VardisonManager";
      };
   }
   //Setup default params
   $TWM2::VardisonManager.lastAttackTime = getRealTime();
   $TWM2::VardisonManager.minionCount = 0;
   $TWM2::VardisonManager.orbObject = -1;
}

function StartVardison1(%position) {
   CheckVardisonManager();
   //Trip the boss manager so nothing else fires up in the initial 10 seconds.
   $TWM2::BossGoing = 1;
   //Erupt a firestorm in his coming....
   // They shall know fear xD
   MessageAll('msgAdminForce', "\c5"@$TWM2::Vardison_DMsg[$TWM2::VardisonDifficulty]);
   //Adjust Position
   %spawnPos = getWord(%position, 0) SPC getWord(%position, 1) SPC getTerrainHeight(%position);
   //First Spawn The Firestorm & Sound FX
   MessageAll('msgSound', "~wfx/environment/wind_sandstorm.wav");
   MessageAll('msgSound', "~wfx/environment/snowstorm1.wav");
   schedule(1500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(2500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(3500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(5000, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(5500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(7500, 0, MessageAll, 'msgSound', "~wfx/armor/breath_bio_uw.wav");
   schedule(10000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   schedule(10000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   schedule(10000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   %fire = new ParticleEmissionDummy(){
      position = vectoradd(%spawnPos, "0 0 0.5");
      dataBlock = "defaultEmissionDummy";
      emitter = "SummoningPierEmitter";
   };
   MissionCleanup.add(%fire);
   %fire.schedule(10000, "delete");
   //Spawn the fake hologram vardison.
   %fakeHolo = new StaticShape(){
      Datablock = "InitialVaridionHoloArmor";
   };
   %fakeHolo.setTransform(vectorAdd(%spawnPos, "0 0 0.25"));
   %fakeHolo.startfade(0, 0, true);
   %fakeHolo.schedule(1000, startfade, 2500, 0, false);
   %fakeHolo.schedule(7500, startfade, 2500, 0, true);
   %fakeHolo.schedule(10000, "Delete");
   //And then start the real one...
   schedule(10000, 0, SpawnVardison, %spawnPos);
}

function SpawnVardison(%position) {
   %Boss = new player(){
      Datablock = "VardisonStageOneArmor";
   };
   %Cpos = vectorAdd(%position, "0 0 5");

   %Boss.isMultiPhaseBoss = true;
   %Boss.isFirstPhase = true;
   %Boss.isFinalPhase = false;

   InitiateBoss(%Boss, "Vardison1");

   %Boss.team = 30;
   %Boss.target = createTarget(%Boss, "\c7Lord Vardison", "", "Derm3", '', %Boss.team, PlayerSensor);
   setTargetSensorData(%Boss.target, PlayerSensor);
   setTargetSensorGroup(%Boss.target, 30);
   setTargetName(%Boss.target, addtaggedstring("\c7Lord Vardison"));
   setTargetSkin(%Boss.target, 'Horde');
   
   %Boss.setTransform(%Cpos);
   %Boss.phase = 1;
   MissionCleanup.add(%Boss);
   
   %Boss.lastKillCount = $TWM2::BossManager.bossKills;
   %Boss.canSummonMinions = true;
   $TWM2::VardisonManager.Vardison = %Boss;
   
   %Boss.thinkSched = schedule(2500, 0, VardisonThink, %Boss);
}

function SpawnVardison2(%position) {
   schedule(250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(750, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1000, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1100, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");

   %Boss = new player(){
      Datablock = "VardisonStageTwoArmor";
   };
   %Cpos = vectorAdd(%position, "0 0 5");

   %Boss.isMultiPhaseBoss = true;
   %Boss.isFirstPhase = false;
   %Boss.isFinalPhase = false;

   InitiateBoss(%Boss, "Vardison2");

   %Boss.team = 30;
   %Boss.target = createTarget(%Boss, "\c7Lord Vardison", "", "Derm3", '', %Boss.team, PlayerSensor);
   setTargetSensorData(%Boss.target, PlayerSensor);
   setTargetSensorGroup(%Boss.target, 30);
   setTargetName(%Boss.target, addtaggedstring("\c7Lord Vardison"));
   setTargetSkin(%Boss.target, 'Horde');

   %Boss.setTransform(%Cpos);
   %Boss.phase = 2;
   MissionCleanup.add(%Boss);

   %Boss.lastKillCount = $TWM2::BossManager.bossKills;
   %Boss.canSummonMinions = true;
   $TWM2::VardisonManager.Vardison = %Boss;
   
   //If we're on difficulty level 4, summon an orb :P
   if($TWM2::VardisonDifficulty >= 4) {
      VardisonSummonOrb(%Boss);
   }

   %Boss.thinkSched = schedule(1000, 0, VardisonThink, %Boss);
}

function SpawnVardison3(%position) {
   schedule(250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(750, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1000, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1100, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1250, 0, MessageAll, 'msgSound', "~wfx/armor/breath_bio_uw.wav");
   schedule(1250, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   schedule(1250, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   schedule(1250, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");

   %Boss = new player(){
      Datablock = "VardisonStageThreeArmor";
   };
   %Cpos = vectorAdd(%position, "0 0 5");

   %Boss.isMultiPhaseBoss = true;
   %Boss.isFirstPhase = false;
   %Boss.isFinalPhase = true;

   InitiateBoss(%Boss, "Vardison3");

   %Boss.team = 30;
   %Boss.target = createTarget(%Boss, "\c7Lord Vardison", "", "Derm3", '', %Boss.team, PlayerSensor);
   setTargetSensorData(%Boss.target, PlayerSensor);
   setTargetSensorGroup(%Boss.target, 30);
   setTargetName(%Boss.target, addtaggedstring("\c7Lord Vardison"));
   setTargetSkin(%Boss.target, 'Horde');

   %Boss.setTransform(%Cpos);
   %Boss.phase = 3;
   MissionCleanup.add(%Boss);

   %Boss.lastKillCount = $TWM2::BossManager.bossKills;
   %Boss.canSummonMinions = true;
   $TWM2::VardisonManager.Vardison = %Boss;
   
   //If we're on level 3 or 4, instantly summon the Shadow Orb to kick things off
   if($TWM2::VardisonDifficulty >= 3) {
      VardisonSummonOrb(%Boss);
   }

   %Boss.thinkSched = schedule(1000, 0, VardisonThink, %Boss);
}

function VardisonThink(%Boss) {
   if(!isObject(%Boss) || %Boss.getState() $= "Dead") {
      //Kill this think instance, let the next one take over.
      return;
   }
   if(%Boss.busy) {
      //I'm currently doing something, check back soon.
      %Boss.thinkSched = schedule(200, 0, VardisonThink, %Boss);
      return;
   }
   %dLevel = $TWM2::VardisonDifficulty;
   %lastAtt = $TWM2::VardisonManager.lastAttackTime; //<--- Note: This value is from the time the last attack ENDED
   %cTime = getRealTime();
   %lastKC = %Boss.lastKillCount;
   %nowKC = $TWM2::BossManager.bossKills;
   %Boss.lastKillCount = $TWM2::BossManager.bossKills;
   //Possible Outcomes...
   %needAttack = false;
   %needMinions = false;
   %needOrbSummon = false;
   %needMove = false;
   //Check for anti-fall....
   if(getWord(%Boss.getPosition(), 2) < (getTerrainHeight(%Boss.getPosition()) - 250)) {
      if(getWord(%Boss.getVelocity(), 2) < -1) {
         //Block the fall... bring us back up...
         echo("VardisonThink(): Anti-Fall Countermeasures activated.");
         %Boss.setPosition(getWord(%Boss.getPosition(), 0) SPC getWord(%Boss.getPosition(), 1) SPC getTerrainHeight(%Boss.getPosition()) + 15);
         %Boss.setVelocity("0 0 1");
         %Boss.startfade(0, 0, true);
         %Boss.schedule(250, startfade, 1000, 0, false);
      }
   }
   //Determine the correct action.
   switch(%Boss.phase) {
      case 1:
         //Did I just get a kill?
         if(%nowKC > %lastKC) {
            //Do I need to summon a shadow orb?
            if($TWM2::Vardison1_CanOrb[%dLevel]) {
               //Is there already an active orb?
               if(!isObject($TWM2::VardisonManager.orbObject)) {
                  //Yep, I need to summon it.
                  %needOrbSummon = true;
               }
            }
         }
         if((%cTime - %lastAtt) >= $TWM2::Vardison1_AttSpeed[%dLevel]) {
            //Time for an attack
            %needAttack = true;
         }
         else {
            //If we're not ready to dish out an attack, let's check what else we need to do...
            // Are we low on minions?
            if($TWM2::VardisonManager.minionCount < $TWM2::Vardison1_MaxMinions[%dLevel]) {
               if(%Boss.canSummonMinions) {
                  //How many players am I up against?
                  %pCount = $HostGamePlayerCount;
                  //How low is my health?
                  %percentage = mCeil((mFloor(%boss.getDamageLeft()*100) / mFloor(%boss.getMaxDamage()*100)) * 100);
                  %BackwardsHP = 100 - %percentage;
                  %chance = %BackwardsHP * %pCount;
                  //Using our test factor, determine if I need minions.
                  if(%chance <= getRandom(1, 100)) {
                     %needMinions = true;
                  }
               }
            }
            //Do I need to be moving towards the enemy?
            %needMove = true; //Phase 1 is always doing this...
         }
      case 2:
         //Did I just get a kill?
         if(%nowKC > %lastKC) {
            //Do I need to summon a shadow orb?
            if($TWM2::Vardison2_CanOrb[%dLevel]) {
               //Is there already an active orb?
               if(!isObject($TWM2::VardisonManager.orbObject)) {
                  //Yep, I need to summon it.
                  %needOrbSummon = true;
               }
            }
         }
         if((%cTime - %lastAtt) >= $TWM2::Vardison2_AttSpeed[%dLevel]) {
            //Time for an attack
            %needAttack = true;
         }
         else {
            //If we're not ready to dish out an attack, let's check what else we need to do...
            // Are we low on minions?
            if($TWM2::VardisonManager.minionCount < $TWM2::Vardison2_MaxMinions[%dLevel]) {
               if(%Boss.canSummonMinions) {
                  //How many players am I up against?
                  %pCount = $HostGamePlayerCount;
                  //How low is my health?
                  %percentage = mCeil((mFloor(%boss.getDamageLeft()*100) / mFloor(%boss.getMaxDamage()*100)) * 100);
                  %BackwardsHP = 100 - %percentage;
                  %chance = %BackwardsHP * %pCount;
                  //Using our test factor, determine if I need minions.
                  if(%chance <= getRandom(1, 100)) {
                     %needMinions = true;
                  }
               }
            }
            %needMove = true;
         }
      case 3:
         //Did I just get a kill?
         if(%nowKC > %lastKC) {
            //Do I need to summon a shadow orb?
            if($TWM2::Vardison3_CanOrb[%dLevel]) {
               //Is there already an active orb?
               if(!isObject($TWM2::VardisonManager.orbObject)) {
                  //Yep, I need to summon it.
                  %needOrbSummon = true;
               }
            }
         }
         if((%cTime - %lastAtt) >= $TWM2::Vardison3_AttSpeed[%dLevel]) {
            //Time for an attack
            %needAttack = true;
         }
         else {
            //If we're not ready to dish out an attack, let's check what else we need to do...
            // Are we low on minions?
            if($TWM2::VardisonManager.minionCount < $TWM2::Vardison3_MaxMinions[%dLevel] && %boss.canSummonMinions) {
               if(%Boss.canSummonMinions) {
                  //How many players am I up against?
                  %pCount = $HostGamePlayerCount;
                  //How low is my health?
                  %percentage = mCeil((mFloor(%boss.getDamageLeft()*100) / mFloor(%boss.getMaxDamage()*100)) * 100);
                  %BackwardsHP = 100 - %percentage;
                  %chance = %BackwardsHP * %pCount;
                  //Using our test factor, determine if I need minions.
                  if(%chance <= getRandom(1, 100)) {
                     %needMinions = true;
                  }
               }
            }
            //Do I need to be moving towards the enemy?
            %needMove = true; //Phase 3 is always doing this...
         }
   }
   //Call the correct function...
   if(%needOrbSummon) {
      VardisonSummonOrb(%Boss);
   }
   else if(%needAttack) {
      VardisonPerformAttack(%Boss);
   }
   else {
      if(%needMinions) {
         VardisonSummonMinions(%Boss);
      }
      if(%needMove) {
         VardisonDoMove(%Boss);
      }
   }
   %Boss.thinkSched = schedule(500, 0, VardisonThink, %Boss);
}

function VardisonDoMove(%Boss) {
   if(!isObject(%Boss) || %Boss.getState() $= "Dead") {
      return;
   }
   %pos = %Boss.getworldboxcenter();
   switch(%Boss.phase) {
      case 1:
         %closest = VardisonGetClosest(%Boss);
         %clDst = getWord(%closest, 1);
         %clPlayer = getWord(%closest, 0).Player;
         if(%clDst < 12) {
            //Perform a sword slam
            VardisonDoSlam(%Boss, %clPlayer);
            return;
         }
         if(%Boss.hastarget != 1){
            %Boss.hastarget = 1;
         }
         %vector = ZgetFacingDirection(%Boss, %clPlayer, %pos);
         %vector = vectorscale(%vector, $Zombie::DForwardSpeed);
         %upvec = "150";
         %x = Getword(%vector,0);
         %y = Getword(%vector,1);
         %z = Getword(%vector,2);
         if(%z >= ($Zombie::DForwardSpeed)) {
            %upvec = (%upvec * 5);
         }
         %vector = %x@" "@%y@" "@%upvec;
         %Boss.applyImpulse(%pos, %vector);
         
      case 2:
         %closest = VardisonGetClosest(%Boss);
         %clDst = getWord(%closest, 1);
         %clPlayer = getWord(%closest, 0).Player;
         if(%clDst < 15) {
            //Perform a sword slam
            VardisonDoSlam(%Boss, %clPlayer);
            return;
         }
         if(%Boss.hastarget != 1){
            %Boss.hastarget = 1;
         }
         %vector = ZgetFacingDirection(%Boss, %clPlayer, %pos);
         %vector = vectorscale(%vector, $Zombie::DForwardSpeed*2);
         %upvec = "150";
         %x = Getword(%vector,0);
         %y = Getword(%vector,1);
         %z = Getword(%vector,2);
         if(%z >= ($Zombie::DForwardSpeed)) {
            %upvec = (%upvec * 5);
         }
         %vector = %x@" "@%y@" "@%upvec;
         %Boss.applyImpulse(%pos, %vector);
         
      case 3:
         %closest = VardisonGetClosest(%Boss);
         %clDst = getWord(%closest, 1);
         %clPlayer = getWord(%closest, 0).Player;
         if(%clDst < 6) {
            //Insta-Kill xD
            %clPlayer.setInvincible(false);
            MessageAll('msgDie', "\c4Lord Vardision: DIE "@getWord(%closest, 0).namebase@"!!!");
            %clPlayer.damage(%boss, %clPlayer.getPosition(), 10000, $DamageType::Idiocy);
            return;
         }
         if(%Boss.hastarget != 1){
            %Boss.hastarget = 1;
         }
         %vector = ZgetFacingDirection(%Boss, %clPlayer, %pos);
         %vector = vectorscale(%vector, $Zombie::DForwardSpeed*5);
         %upvec = "150";
         %x = Getword(%vector,0);
         %y = Getword(%vector,1);
         %z = Getword(%vector,2);
         if(%z >= ($Zombie::DForwardSpeed)) {
            %upvec = (%upvec * 5);
         }
         %vector = %x@" "@%y@" "@%upvec;
         %Boss.applyImpulse(%pos, %vector);
   }
}

function VardisonDoSlam(%Boss, %ToDie) {
   %Boss.busy = true;
   %vector = ZgetFacingDirection(%Boss, %ToDie, %Boss.getWorldBoxCenter());
   %vector = vectorscale(%vector, $Zombie::DForwardSpeed * 7.5);
   %upvec = "150";
   %x = Getword(%vector,0);
   %y = Getword(%vector,1);
   %z = Getword(%vector,2);
   if(%z >= ($Zombie::DForwardSpeed)) {
      %upvec = (%upvec * 5);
   }
   %vector = %x@" "@%y@" "@%upvec;
   %Boss.applyImpulse(%pos, %vector);
   schedule(750, 0, "VardisonFinishSlam", %Boss, %ToDie);
}

function VardisonFinishSlam(%Boss, %ToDie) {
   //Summon the invis-projectile
   %Boss.setMoveState(true);
   %p = new LinearFlareProjectile() {
      dataBlock        = ShadowBladeSlam;
      initialDirection = "0 0 -10";
      initialPosition  = vectorAdd(%ToDie.getPosition(), "0 0 1");
      sourceSlot       = 0;
   };
   %p.sourceObject = %Boss;
   MissionCleanup.add(%p);
   %Boss.schedule(1000, "setMoveState", false);
   ServerPlay3d(BOVHitSound, %ToDie.getPosition());
   ServerPlay3d(BOVHitSound, %ToDie.getPosition());
   ServerPlay3d(BOVHitSound, %ToDie.getPosition());
   $TWM2::VardisonManager.schedule(1000, cooldownOff, %Boss, "busy");
}

function VardisonSummonOrb(%Boss) {
   if(isObject($TWM2::VardisonManager.orbObject)) {
      //Stop, we already have an orb.
      return;
   }
   //Shadow Orb Time...
   MessageAll('msgAttack', "\c5Alert: Lord Vardison Opens The Shadow Rift...");
   schedule(250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(700, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1350, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(1500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav");
   schedule(2000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   schedule(2000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   schedule(2000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav");
   %Boss.busy = true;
   %Boss.rapierShield = true;
   %Boss.setMoveState(true);
   //Fire SFX
   $TWM2::VardisonManager.orbFire = new ParticleEmissionDummy(){
      position = vectoradd(%Boss.getPosition(), "0 0 0.5");
      dataBlock = "defaultEmissionDummy";
      emitter = "SummoningPierEmitter";
   };
   MissionCleanup.add($TWM2::VardisonManager.orbFire);
   //Create the Orb Object
   $TWM2::VardisonManager.schedule(2000, summonOrb, %Boss);
}

function VardisonSummonMinions(%Boss) {
   if(%Boss.canSummonMinions) {
      %currentCount = $TWM2::VardisonManager.minionCount;
      %dLevel = $TWM2::VardisonDifficulty;
      %max = 0;
      switch(%Boss.phase) {
         case 1:
            %max = $TWM2::Vardison1_MaxMinions[%dLevel];
         case 2:
            %max = $TWM2::Vardison2_MaxMinions[%dLevel];
         case 3:
            %max = $TWM2::Vardison3_MaxMinions[%dLevel];
      }
      %factor = %dLevel / 4;
      %Low = 1;
      %High = mCeil((%max - %currentCount) * %factor);
      for(%i = 0; %i < getRandom(%Low, %High); %i++) {
         VardisonDoMinionSummon(%Boss);
      }
      %Boss.canSummonMinions = false;
      $TWM2::VardisonManager.schedule($TWM2::Vardison_MinionCooldown[%dLevel] * 1000, cooldownOff, %Boss, "minions");
   }
}

function VardisonDoMinionSummon(%Boss) {
   %posSpawn = vectorAdd(%Boss.getPosition(), TWM2Lib_MainControl("getRandomPosition", 50 TAB 1));
   %spawnFire = new ParticleEmissionDummy(){
      position = vectoradd(%posSpawn, "0 0 0.5");
      dataBlock = "defaultEmissionDummy";
      emitter = "SummoningPierEmitter";
   };
   MissionCleanup.add(%spawnFire);
   %spawnFire.schedule(500, "delete");
   schedule(650, 0, SpawnVMinion, %posSpawn);
}

function SpawnVMinion(%position) {
   %minion = StartAZombie(%position, 17);
   if(isObject(%minion)) {
      //Apply minion settings & increase count
      $TWM2::VardisonManager.minionCount++;
      %minion.isBossMinion = true;
      %minion.isVardisonMinion = true;
   }
}

function VardisonGetClosest(%Boss) {
   %wbpos = %Boss.getworldboxcenter();
   %count = ClientGroup.getCount();
   %closestClient = -1;
   %closestDistance = 32767;
   for(%i = 0; %i < %count; %i++) {
      %cl = ClientGroup.getObject(%i);
      if(isObject(%cl.player)){
         %testPos = %cl.player.getWorldBoxCenter();
         %distance = vectorDist(%wbpos, %testPos);
         if (%distance > 0 && %distance < %closestDistance) {
            %closestClient = %cl;
            %closestDistance = %distance;
         }
      }
   }
   return %closestClient SPC %closestDistance;
}

function VardisonPerformAttack(%Boss) {
   //The do-all opening function for Vardison's attacks
   //Start by halting the think() method
   %Boss.busy = true;
   switch(%Boss.phase) {
      case 1:
         %attackSelect = getRandom(1, 5);
         switch(%attackSelect) {
            case 1:
               //Shadow Bomb Strike
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "ShadowBombStrike", %tPl);
                  $TWM2::VardisonManager.schedule(4000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
               
            case 2:
               //Nightmare Missile
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "NightmareMissile", %tPl);
                  $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
               
            case 3:
               //Shadow Fissure
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  %tPos = %tPl.getPosition();
                  %bPos = %Boss.getPosition();
                  %fVec = vectorNormalize(vectorSub(%tPos, %bPos));
                  //Phase Vardison Out To Safety
                  %fire = new ParticleEmissionDummy(){
                     position = vectoradd(%spawnPos, "0 0 0.5");
                     dataBlock = "defaultEmissionDummy";
                     emitter = "SummoningPierEmitter";
                  };
                  MissionCleanup.add(%fire);
                  %fire.schedule(6500, "delete");
                  //Fades & Teleports
                  %Boss.startfade(1500, 0, true);
                  %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10"));
                  schedule(3000, 0, "VardisonNamedAttack", %Boss, "ShadowFissure", %bPos TAB %fVec);
                  %Boss.schedule(6000, setPosition, %bPos);
                  %Boss.schedule(6000, startFade, 1000, 0, false);
                  //
                  $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
               
            case 4:
               //4x Seeker Photon
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  schedule(1000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(2000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(3000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(4000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
               
            case 5:
               //Fire Missile
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "FireSeeker", %tPl);
                  $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
         }
         
      case 2:
         %attackSelect = getRandom(1, 8);
         switch(%attackSelect) {
            case 1:
               //Shadow Bomb Strike
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "ShadowBombStrike", %tPl);
                  $TWM2::VardisonManager.schedule(4000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 2:
               //Nightmare Missile
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "NightmareMissile", %tPl);
                  $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 3:
               //Shadow Fissure
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  %tPos = %tPl.getPosition();
                  %bPos = %Boss.getPosition();
                  %fVec = vectorNormalize(vectorSub(%tPos, %bPos));
                  //Phase Vardison Out To Safety
                  %fire = new ParticleEmissionDummy(){
                     position = vectoradd(%spawnPos, "0 0 0.5");
                     dataBlock = "defaultEmissionDummy";
                     emitter = "SummoningPierEmitter";
                  };
                  MissionCleanup.add(%fire);
                  %fire.schedule(6500, "delete");
                  //Fades & Teleports
                  %Boss.startfade(1500, 0, true);
                  %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10"));
                  schedule(3000, 0, "VardisonNamedAttack", %Boss, "ShadowFissure", %bPos TAB %fVec);
                  %Boss.schedule(6000, setPosition, %bPos);
                  %Boss.schedule(6000, startFade, 1000, 0, false);
                  //
                  $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 4:
               //4x Seeker Photon
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  schedule(1000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(2000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(3000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(4000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 5:
               //Minion Army
               VardisonNamedAttack(%Boss, "MinionFlood", "");

            case 6:
               //Stasis Gate
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player.getPosition();
                  VardisonNamedAttack(%Boss, "StasisGate", %tPl);
                  $TWM2::VardisonManager.schedule(10000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 7:
               //Rift Gate
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player.getPosition();
                  VardisonNamedAttack(%Boss, "RiftGate", %tPl);
                  $TWM2::VardisonManager.schedule(10000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 8:
               //SGF
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "SolomentaryGravityFlux", %tPl TAB 0);
                  $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
         }

      case 3:
         %attackSelect = getRandom(1, 7);
         switch(%attackSelect) {
            case 1:
               //Shadow Bomb Strike
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "ShadowBombStrike", %tPl);
                  $TWM2::VardisonManager.schedule(4000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 2:
               //Nightmare Missile
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "NightmareMissile", %tPl);
                  $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 3:
               //Shadow Fissure
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  %tPos = %tPl.getPosition();
                  %bPos = %Boss.getPosition();
                  %fVec = vectorNormalize(vectorSub(%tPos, %bPos));
                  //Phase Vardison Out To Safety
                  %fire = new ParticleEmissionDummy(){
                     position = vectoradd(%spawnPos, "0 0 0.5");
                     dataBlock = "defaultEmissionDummy";
                     emitter = "SummoningPierEmitter";
                  };
                  MissionCleanup.add(%fire);
                  %fire.schedule(6500, "delete");
                  //Fades & Teleports
                  %Boss.startfade(1500, 0, true);
                  %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10"));
                  schedule(3000, 0, "VardisonNamedAttack", %Boss, "ShadowFissure", %bPos TAB %fVec);
                  %Boss.schedule(6000, setPosition, %bPos);
                  %Boss.schedule(6000, startFade, 1000, 0, false);
                  //
                  $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 4:
               //4x Seeker Photon
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  schedule(1000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(2000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(3000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  schedule(4000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl);
                  $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }

            case 5:
               //Laser Drop
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  VardisonNamedAttack(%Boss, "LaserDrop", %tPl);
                  $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
               
            case 6:
               //Laser Wall
               %Boss.setMoveState(true);
               %target = FindValidTarget(%Boss);
               if(isObject(%target)) {
                  %tPl = %target.player;
                  for(%i = 0; %i < 25; %i++) {
                     schedule(50+(%i*150), 0, VardisonNamedAttack, %Boss, "LaserWall", %tPl);
                  }
                  $TWM2::VardisonManager.schedule(10000, cooldownOff, %Boss, "attackFinished");
               }
               else {
                  %Boss.setMoveState(false);
                  %Boss.busy = false;
               }
               
            case 7:
               //Gravity Well
               %Boss.setMoveState(true);
               VardisonNamedAttack(%Boss, "GravityWell", 0);
               $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished");
         }
      
   }
}

function VardisonNamedAttack(%Boss, %attack, %args) {
   if(!isObject(%Boss) || %Boss.getState() $= "Dead") {
      return;
   }
   %bPos = %Boss.getPosition();
   
   switch$(%attack) {
      case "ShadowBombStrike":
         //Spawn 4 Pulses Above Vardison Fired at a guy
         %target = getField(%args, 0);
         %sPos = vectorAdd(%bPos, "0 0 25");
         %vec = vectorNormalize(vectorSub(%target.getPosition(), %sPos));
         for(%i = 0; %i < 4; %i++) {
            %p = new LinearFlareProjectile() {
               dataBlock        = ShadowBlastBolt;
               initialDirection = vectorScale(%vec, 10);
               initialPosition  = %sPos;
               sourceSlot       = 4;
            };
            %p.sourceObject = %Boss;
            MissionCleanup.add(%p);
         }
         
      case "NightmareMissile":
         %target = getField(%args, 0);
         %sPos = vectorAdd(%bPos, "0 0 25");
         %vec = vectorNormalize(vectorSub(%target.getPosition(), %sPos));
   	     %p = new SeekerProjectile() {
            dataBlock        = YvexNightmareMissile;
            initialDirection = %vec;
            initialPosition  = %sPos;
            sourceSlot       = 4;
         };
         %p.sourceObject     = %Boss;
   	     %beacon = new BeaconObject() {
            dataBlock = "SubBeacon";
            beaconType = "vehicle";
            position = %target.getWorldBoxCenter();
         };
   	     %beacon.team = 0;
   	     %beacon.setTarget(0);
   	     MissionCleanup.add(%beacon);
         %p.setObjectTarget(%beacon);
         DemonMotherMissileFollow(%target, %beacon, %p);
         
      case "ShadowFissure":
         %sPos = getField(%args, 0);
         %fVec = getField(%args, 1);
         for(%i = 1; %i < 20; %i++) {
            %sPos = vectorAdd(%sPos, "0 0 0.5");
            %sPos = vectorAdd(%sPos, vectorScale(%fVec, %i*3));
            %p = new LinearFlareProjectile() {
               dataBlock        = ShadowBlastBolt;
               initialDirection = "0 0 -15";
               initialPosition  = %sPos;
               sourceSlot       = 4;
            };
            %p.sourceObject = %Boss;
            MissionCleanup.add(%p);
         }
         
      case "SeekerPhoton":
         %target = getField(%args, 0);
         FireSeekerPhotons(%Boss, %target);
         
      case "FireSeeker":
         %target = getField(%args, 0);
         %sPos = vectorAdd(%bPos, "0 0 25");
         %vec = vectorNormalize(vectorSub(%target.getPosition(), %sPos));
         %p = new SeekerProjectile() {
            dataBlock        = VegenorFireMissile;
            initialDirection = %vec;
            initialPosition  = %sPos;
            sourceSlot       = 4;
         };
         %p.sourceObject     = %Boss;
         %beacon = new BeaconObject() {
            dataBlock = "SubBeacon";
            beaconType = "vehicle";
            position = %target.getWorldBoxCenter();
         };
         %beacon.team = 0;
         %beacon.setTarget(0);
         MissionCleanup.add(%beacon);
         %p.setObjectTarget(%beacon);
         DemonMotherMissileFollow(%target, %beacon, %p);
         
      case "MinionFlood":
         //Summon Maximum Minions & then Phase out until the team drops them
         %max = $TWM2::Vardison2_MaxMinions[$TWM2::VardisonDifficulty];
         %lowEnd = mFloor(%max * 0.25);
         %retPos = %bPos;
         %current = $TWM2::VardisonManager.minionCount;
         %need = %max - %current;
         for(%i = 0; %i < %need; %i++) {
            VardisonDoMinionSummon(%Boss);
         }
         //Meanwhile, I take my leave :)
         %Boss.startfade(1500, 0, true);
         %Boss.rapierShield = true;
         %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10"));
         %Boss.vmcountLoop = schedule(1000, 0, VardisonMinionCountCheckup, %Boss, %retPos, %lowEnd);
         
      case "StasisGate":
         %pos = getField(%args, 0);
         %TargetSearchMask = $TypeMasks::PlayerObjectType;
         %c = createEmitter(%pos, FlashLEmitter, "1 0 0");      //Rotate it
         %c.schedule(1000, delete);
         InitContainerRadiusSearch(%pos, 25, %TargetSearchMask);
         while ((%potentialTarget = ContainerSearchNext()) != 0){
            if (!%potentialTarget.isZombie && !%potentialTarget.isBoss && !%potentialTarget.isVardisonMinion) {
               VardisonNamedAttack(%Boss, "StasisLoop", %potentialTarget TAB 0);
            }
         }
         
      case "StasisLoop":
         %pl = getField(%args, 0);
         if(!isObject(%pl) || %pl.getState() $= "dead") {
            return;
         }
         %counter = getField(%args, 1);
         %counter++;
         if(%counter > 10) {
            %pl.setMoveState(false);
            return;
         }
         %c = createEmitter(%pl.getPosition(), PBCExpEmitter, "1 0 0");      //Rotate it
         %c.schedule(1000, delete);
         %pl.setMoveState(true);
         schedule(1000, 0, VardisonNamedAttack, %Boss, %attack, %pl TAB %counter);
      
      case "RiftGate":
         %pos = getField(%args, 0);
         %goPos = TWM2Lib_MainControl("RMPG");
         %TargetSearchMask = $TypeMasks::PlayerObjectType;
         %c = createEmitter(%pos, FlashLEmitter, "1 0 0");      //Rotate it
         %c.schedule(1000, delete);
         %c2 = createEmitter(%goPos, FlashLEmitter, "1 0 0");      //Rotate it
         %c2.schedule(1000, delete);
         InitContainerRadiusSearch(%pos, 25, %TargetSearchMask);
         while ((%potentialTarget = ContainerSearchNext()) != 0){
            if (!%potentialTarget.isZombie && !%potentialTarget.isBoss && !%potentialTarget.isVardisonMinion) {
               %PosAdd = vectorNormalize(vectorSub(%pos, %potentialTarget.getPosition()));
               %PosDst = vectorDist(%pos, %potentialTarget.getPosition());
               %newPos = vectorAdd(%goPos, vectorScale(%PosAdd, %PosDst));
               %potentialTarget.setPosition(%newPos);
            }
         }
      
      case "LaserDrop":
         %toDie = getField(%args, 0);
         if(!isObject(%toDie) || %toDie.getState() $= "dead") {
            return;
         }
         %p = new LinearFlareProjectile() {
            dataBlock        = HyperDevestatorBeam;
            initialDirection = "0 0 -10";
            initialPosition  = vectoradd(%toDie.getPosition(), "0 0 500");
            sourceSlot       = 4;
         };
         %p.sourceObject     = %boss;
         MissionCleanup.add(%p);
      
      case "LaserWall":
         %toDie = getField(%args, 0);
         if(!isObject(%toDie) || %toDie.getState() $= "dead") {
            return;
         }
         %vec = vectorNormalize(vectorSub(%toDie.getPosition(), %bPos));
         %p = new LinearFlareProjectile() {
            dataBlock        = SuperlaserProjectile;
            initialDirection = %vec;
            initialPosition  = %bPos;
            sourceObject     = %boss;
            sourceSlot       = 4;
         };
         MissionCleanup.add(%p);
      
      case "SolomentaryGravityFlux":
         %target = getField(%args, 0);
         if(!isObject(%target) || %target.getState() $= "dead") {
            return;
         }
         %counter = getField(%args, 1);
         %counter++;
         if(%counter < 15) {
            %target.setVelocity("0 0 300");
         }
         else if(%counter > 25) {
            //Stop...
            return;
         }
         else {
            %target.setVelocity("0 0 -300");
         }
         schedule(150, 0, VardisonNamedAttack, %Boss, %attack, %target TAB %counter);
      
      case "GravityWell":
         %counter = getField(%args, 0);
         %counter++;
         if(%counter < 15) {
            for(%i = 0; %i < ClientGroup.getCount(); %i++) {
               %cl = ClientGroup.getObject(%i);
               if(isObject(%cl.player) || %cl.player.getState() !$= "dead") {
                  %cl.player.setVelocity("0 0 300");
               }
            }
         }
         else if(%counter > 25) {
            //Stop...
            return;
         }
         else {
            for(%i = 0; %i < ClientGroup.getCount(); %i++) {
               %cl = ClientGroup.getObject(%i);
               if(isObject(%cl.player) || %cl.player.getState() !$= "dead") {
                  %cl.player.setVelocity("0 0 -300");
               }
            }
         }
         schedule(150, 0, VardisonNamedAttack, %Boss, %attack, %counter);

      default:
         error("Invalid vardison attack...");
   }
}

function VardisonMinionCountCheckup(%boss, %retPos, %lowEnd) {
   if($TWM2::VardisonManager.minionCount < %lowEnd) {
      //Return to the arena
      %Boss.schedule(1500, setPosition, %retPos);
      %Boss.schedule(1500, startFade, 1000, 0, false);
      %Boss.rapierShield = false;
      $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished");
      return;
   }
   %boss.vmcountLoop = schedule(1000, 0, VardisonMinionCountCheckup, %boss, %retPos, %lowEnd);
}

//Vardison Manager Functions
//SummonOrb()
function VardisonManager::summonOrb(%this, %boss) {
   %summonPos = vectorAdd(%boss.getPosition(), "0 0 35");
   %orb = new (StaticShape)() {
      dataBlock = ShadowOrb;
   };
   %orb.setTransform(%summonPos SPC "0 0 0 1");
   %orb.team = %boss.Team;
   %orb.setOwner(%boss);

   %orb.team = 30;
   %orb.target = createTarget(%orb, "\c7Shadow Rift", "", "Derm3", '', %orb.team, PlayerSensor);
   setTargetSensorData(%orb.target, PlayerSensor);
   setTargetSensorGroup(%orb.target, 30);
   setTargetName(%orb.target, addtaggedstring("\c7Shadow Rift"));
   
   %orb.waypoint = new WayPoint() {
      position = %orb.getPosition();
      dataBlock = "WayPointMarker";
      team = %boss.Team;
      name = "Shadow Rift";
   };
   
   %orb.startfade(1, 0, true);
   
   //SFX
   $TWM2::VardisonManager.OrbSFX = new ParticleEmissionDummy(){
      position = %orb.getPosition();
      dataBlock = "defaultEmissionDummy";
      emitter = "ShadowOrbEmitter";
   };
   MissionCleanup.add($TWM2::VardisonManager.OrbSFX);
   //
   %this.orbKillSched = %this.schedule($TWM2::Vardison_OrbKillTime, orbKill, %boss, %orb);
}

function VardisonManager::orbKill(%this, %boss, %orb) {
   %restoreCount = 0;
   for(%i = 0; %i < ClientGroup.getCount(); %i++) {
      %cl = ClientGroup.getObject(%i);
      if(isObject(%cl.player) && %cl.player.getState() !$= "dead") {
         //Bye Bye :)
         %cl.player.rapierShield = false;
         %cl.player.setInvincible(false);
         %cl.player.damage(%boss, %cl.player.getPosition(), 10000, $DamageType::ShadowOrb);
         %cl.player.blowup();
         MessageAll('msgDeath', "\c2"@%cl.namebase@" has been annihilated by the Shadow Rift.");
         //If Vardison Restores HP from rift kills, do that now :P
         if($TWM2::Vardison_OrbRegenHP[$TWM2::VardisonDifficulty]) {
            %boss.setDamageLevel(%boss.getDamageLevel() - 0.35);
            %restoreCount++;
         }
      }
   }
   MessageAll('msgRestore', "\c5Lord Vardison has absorbed the life energy of "@%restoreCount@" combatants.");
   %wipeEmit = new ParticleEmissionDummy(){
      position = %orb.getPosition();
      dataBlock = "defaultEmissionDummy";
      emitter = "ShadowOrbDetonationEmitter";
   };
   %wipeEmit.schedule(500, "delete");
   //Delete the orb & it's effects
   if(isObject(%obj.waypoint)) {
      %obj.waypoint.schedule(500, "delete");
   }
   if(isObject($TWM2::VardisonManager.OrbSFX)) {
      $TWM2::VardisonManager.OrbSFX.schedule(500, "delete");
   }
   %orb.schedule(500, "delete");
   if(isObject(%this.orbFire)) {
      %this.orbFire.schedule(500, "delete");
   }
   %this.orbObject = -1;
   %boss.rapierShield = false;
   %boss.busy = false; //<-- let think() resume...
}

function VardisonManager::orbDestroyed(%this) {
   if(isObject(%this.orbFire)) {
      %this.orbFire.schedule(500, "delete");
   }
   cancel(%this.orbKillSched);
   %this.orbObject = -1;
   %boss = %this.Vardison;
   %boss.rapierShield = false;
   %boss.busy = false; //<-- let think() resume...
   MessageAll('msgDeath', "\c2The Shadow Rift has been Shattered...");
}

function VardisonManager::cooldownOff(%this, %Boss, %type) {
   if(!isObject(%this)) {
      error("VardisonManager::cooldownOff(): Missing instance of VM.");
      return;
   }
   if(!isObject(%Boss) || %Boss.getState() $= "dead") {
      error("VardisonManager::cooldownOff(): Vardison Dead.");
      return;
   }
   switch$(%type) {
      case "minions":
         %Boss.canSummonMinions = true;

      case "busy":
         %Boss.busy = false;
         
      case "attackFinished":
         //Unlock the boss & update LAT
         %Boss.setMoveState(false);
         %this.lastAttackTime = getRealTime();
         %Boss.busy = false;
   }
}

function ShadowOrb::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType) {
   if(%sourceObject && %targetObject.isEnabled()) {
      if(%sourceObject.client) {
         %targetObject.lastDamagedBy = %sourceObject.client;
         %targetObject.lastDamagedByTeam = %sourceObject.client.team;
         %targetObject.damageTimeMS = GetSimTime();
      }
      else {
         %targetObject.lastDamagedBy = %sourceObject;
         %targetObject.lastDamagedByTeam = %sourceObject.team;
         %targetObject.damageTimeMS = GetSimTime();
      }
   }
   if (%data.isShielded) {
      %amount = %data.checkShields(%targetObject, %position, %amount, %damageType);
   }
   %damageScale = %data.damageScale[%damageType];
   if(%damageScale !$= "") {
      %amount *= %damageScale;
   }
   if (%amount > 0) {
      %targetObject.applyDamage(%amount);
   }
}
