From 739d77d1e2e9d590b4e0cb66307f45852e986968 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Wed, 11 Oct 2017 11:46:41 -0500 Subject: [PATCH] Change set 10/11 Adds all of the progress as of 10/11. NOTE: Do not run the mod right now as there are a lot of features that won't work (IE: Player Zombies, All Zombie Types other than Normal). --- README.md | 27 + scripts/HelljumpGame.cs | 2 +- scripts/HordeGame.cs | 2 +- scripts/TWM2/ArmorFunctions.cs | 102 +-- scripts/TWM2/Bosses/ColonelWindshear.cs | 34 +- scripts/TWM2/Bosses/GeneralVegenor.cs | 6 +- scripts/TWM2/Bosses/LordRog.cs | 8 +- scripts/TWM2/Bosses/LordVardison.cs | 20 +- scripts/TWM2/Bosses/LordYvex.cs | 37 +- scripts/TWM2/Bosses/MajorInsignia.cs | 8 +- scripts/TWM2/Bosses/ShadeLord.cs | 5 + scripts/TWM2/ChatCommands/Admin.cs | 4 +- scripts/TWM2/ChatCommands/Public.cs | 4 + scripts/TWM2/ChatCommands/SuperAdmin.cs | 4 + scripts/TWM2/LoadMod.cs | 1 + scripts/TWM2/Missions/Invasion.cs | 190 ++--- scripts/TWM2/Missions/RainDown.cs | 2 +- scripts/TWM2/Systems/LivingWorldMode.cs | 66 ++ scripts/TWM2/Systems/MainControl.cs | 19 +- scripts/TWM2/Systems/ObjectDamage.cs | 20 + scripts/TWM2/Zombie/LoadZombieScripts.cs | 3 +- scripts/TWM2/Zombie/PlayerZombieAttacks.cs | 2 +- scripts/TWM2/Zombie/ZombieCore.cs | 570 ++++++++++++++ scripts/TWM2/Zombie/ZombieTypes/DemonLord.cs | 2 +- scripts/TWM2/Zombie/ZombieTypes/Normal.cs | 150 ++-- scripts/TWM2/Zombie/ZombieTypes/Ravager.cs | 74 ++ scripts/TWM2/Zombie/ZombieTypes/Shifter.cs | 11 +- scripts/TWM2/Zombie/ZombieTypes/Sniper.cs | 21 + scripts/TWM2/Zombie/ZombieTypes/Summoner.cs | 2 +- .../Zombie/ZombieTypes/VolatileRavager.cs | 110 +++ scripts/admin.cs | 710 ++++++++---------- scripts/defaultGame.cs | 99 ++- scripts/item.cs | 64 +- scripts/packs/Medpack.cs | 2 +- scripts/packs/ZSpawnpack.cs | 26 +- scripts/player.cs | 24 +- scripts/vehicles/vehicle_havoc.cs | 4 +- 37 files changed, 1689 insertions(+), 746 deletions(-) create mode 100644 scripts/TWM2/Systems/LivingWorldMode.cs create mode 100644 scripts/TWM2/Zombie/ZombieCore.cs create mode 100644 scripts/TWM2/Zombie/ZombieTypes/Ravager.cs create mode 100644 scripts/TWM2/Zombie/ZombieTypes/VolatileRavager.cs diff --git a/README.md b/README.md index 7aebb2e..efce814 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,36 @@ MOD DEVELOPMENT HISTORY (GIT VERSIONS): PLEASE NOTE: For the Legacy (Pre-GitHub Versions) Changelogs, please see LEGACY CHANGELOG.md 3.91 -> 3.92 (In Progress): +* Zombie Changes + * Global + * Massive "spring cleaning" of the zombie code files, fixing a bunch of bad coding practices and a few logic errors. + * Redid the zombie targeting and movement methods to make them much "smoother" + * This was done by slicing the movement loop down to 100ms from 500ms. + * To compensate, all zombie speeds were reduced by 5x. + * Moved all functioning into a core control script, added additional modifiers and flags to grant more customizability to zombies + * **Only Normal Zombies are functional at this moment in time** * Added Boss Proficiency * Hidden challenges embedded in boss fights that award additional experience for completing tough feats * For example: Defeat the shade lord without dying by the elemental shades +* Living World Mode + * Added a new option for admins to toggle (Living World) in the Construction Mode. Players will be able to vote toggle this option + * This aspect of the update will be coming soon... +* Boss Balancing / Updates: + * All Bosses + * Testing a new difficulty system + * Boss health damage will now scale to the number of players in the game + * Boss attack damage also now scales to the number of players in the game + * NOTE: Some attacks are still designated OHK attacks and will not be affected + * This will allow solo players a fighting chance to actually fight against the bosses + * For the time being, this change will only apply to the Lord Yvex fight, if testing goes well, I will adapt to other bosses + * Colonel Windshear + * Addressed a silly bug with the Colonel Windshear fight that caused the platform turrets to be on a different team than the gunship + * The Harbinger Gunship allies will now properly target players instead of shooting their leader + * Colonel Windshear can now call for additional air support during the fight + * Stormrider + * Re-did his ground detection script to "hopefully" eradicate those funny moments when he suicide bombs the ground, ending the fight + * Lord Vardison + * Fixed an erraneous text prompt that would appear when the shadow rift detonated outside of WTF difficulty stating vardison had healed when in fact he did not 3.9 -> 3.91: * Reduced the requirement to order missions to the rank of General (49) from Commanding Officer (59) diff --git a/scripts/HelljumpGame.cs b/scripts/HelljumpGame.cs index 2b1ef48..73f7b83 100644 --- a/scripts/HelljumpGame.cs +++ b/scripts/HelljumpGame.cs @@ -972,7 +972,7 @@ function HelljumpGame::SpawnZombies(%game, %pos, %type) { } %c = CreateEmitter(%pos, NightmareGlobeEmitter, "0 0 1"); %c.schedule(1000, "delete"); - schedule(500, 0, "StartAZombie", %pos, %type); + schedule(500, 0, "TWM2Lib_Zombie_Core", "SpawnZombie", "zSpawnCommand", %type, %pos); } function HelljumpGame::StartWave(%game, %wave) { diff --git a/scripts/HordeGame.cs b/scripts/HordeGame.cs index cebebc5..3875bd4 100644 --- a/scripts/HordeGame.cs +++ b/scripts/HordeGame.cs @@ -686,7 +686,7 @@ function HordeSpawnZombies(%pos, %type) { } %c = CreateEmitter(%pos, NightmareGlobeEmitter, "0 0 1"); %c.schedule(1000, "delete"); - schedule(500, 0, "StartAZombie", %pos, %type); + schedule(500, 0, "TWM2Lib_Zombie_Core", "SpawnZombie", "zSpawnCommand", %type, %pos); } function StartHordeZombies(%mission, %wave) { diff --git a/scripts/TWM2/ArmorFunctions.cs b/scripts/TWM2/ArmorFunctions.cs index 276dd9c..eac10e3 100644 --- a/scripts/TWM2/ArmorFunctions.cs +++ b/scripts/TWM2/ArmorFunctions.cs @@ -279,55 +279,54 @@ function LordZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { } } +function SniperZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { + if (%triggerNum == 0) { //shooting + if(%player.RecentAttack["Shot"] == 1) { + return; + } + else { + %player.RecentAttack["Shot"] = 1; + schedule(3000, 0, "ResetPlayerDLAttack", %player, "Shot"); + %p = new TracerProjectile() { //TWM2 Sniper zombies use M1 Snipers :P + dataBlock = M1Bullet; + initialDirection = %player.getMuzzleVector(4); + initialPosition = %player.getMuzzlePoint(4); + sourceObject = %player; + sourceSlot = 4; + }; + ServerPlay3D(M1FireSound, %player.getPosition()); + } + } + if(%triggerNum == 3) { + %pos = %player.getPosition(); + %vector = %player.getMuzzleVector(4); + %x = getWord(%vector, 0); + %y = getWord(%vector, 1); + %finX = %x * -1; + %finY = %y * -1; + %finalVec = %finX SPC %finY SPC 0; + %finalVec = VectorScale(%finalVec, $Zombie::DForwardSpeed * 3); + //Z is unimportant + %player.applyImpulse(%pos, %finalVec); + } +} + function DemonZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { - if(%player.isSniperZombie) { - if (%triggerNum == 0) { //shooting - if(%player.RecentAttack["Shot"] == 1) { - return; - } - else { - %player.RecentAttack["Shot"] = 1; - schedule(3000, 0, "ResetPlayerDLAttack", %player, "Shot"); - %p = new TracerProjectile() { //TWM2 Sniper zombies use M1 Snipers :P - dataBlock = M1Bullet; - initialDirection = %player.getMuzzleVector(4); - initialPosition = %player.getMuzzlePoint(4); - sourceObject = %player; - sourceSlot = 4; - }; - ServerPlay3D(M1FireSound, %player.getPosition()); - } - } - if(%triggerNum == 3) { - %pos = %player.getPosition(); - %vector = %player.getMuzzleVector(4); - %x = getWord(%vector, 0); - %y = getWord(%vector, 1); - %finX = %x * -1; - %finY = %y * -1; - %finalVec = %finX SPC %finY SPC 0; - %finalVec = VectorScale(%finalVec, $Zombie::DForwardSpeed * 3); - //Z is unimportant - %player.applyImpulse(%pos, %finalVec); - } - } - else { - if (%triggerNum == 0) { //shooting - if(%player.recharging) { - return; - } - %p = new GrenadeProjectile() { - dataBlock = DemonFireball; - initialDirection = %player.getMuzzleVector(0); - initialPosition = vectoradd(%player.getMuzzlePoint(0), "0 0 1.5"); - sourceObject = %player; - sourceSlot = 6; - }; - MissionCleanup.add(%p); - %player.recharging = 1; - schedule(4000,0,"ResetZombieCharge",%player); - } - } + if (%triggerNum == 0) { //shooting + if(%player.recharging) { + return; + } + %p = new GrenadeProjectile() { + dataBlock = DemonFireball; + initialDirection = %player.getMuzzleVector(0); + initialPosition = vectoradd(%player.getMuzzlePoint(0), "0 0 1.5"); + sourceObject = %player; + sourceSlot = 6; + }; + MissionCleanup.add(%p); + %player.recharging = 1; + schedule(4000,0,"ResetZombieCharge",%player); + } } function RapierZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { @@ -618,7 +617,7 @@ function SummonerZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { %c.schedule(((%Ct * 1000) + 500), "delete"); for(%i = 1; %i <= %ct; %i++) { %time = %i * 1000; - schedule(%time, 0, "StartAZombie", %SumPos, %type); + schedule(%time, 0, "TWM2Lib_Zombie_Core" "SpawnZombie", "zSpawnCommand", %type, %SumPos); } } } @@ -648,9 +647,9 @@ function DemonUltraZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { } } -function FZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { +function VolatileRavagerZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { if (%triggerNum == 3) { - if(%player.zombieType == 13) { + if(!%player.detonatedVRavC4) { ServerPlay3D("SatchelChargeExplosionSound", %player.getPosition()); %c4 = new Item() { datablock = C4Deployed; @@ -661,6 +660,7 @@ function FZombieArmor::onTrigger(%data, %player, %triggerNum, %val) { schedule(770, 0, "C4GoBoom", %c4); %c4.theClient = %player.client; + %player.detonatedVRavC4 = true; return; } } diff --git a/scripts/TWM2/Bosses/ColonelWindshear.cs b/scripts/TWM2/Bosses/ColonelWindshear.cs index e4b838f..23b04d1 100644 --- a/scripts/TWM2/Bosses/ColonelWindshear.cs +++ b/scripts/TWM2/Bosses/ColonelWindshear.cs @@ -1,20 +1,27 @@ +$Boss::Proficiency["CnlWindshear", 0] = "Team Bronze\t1000\tDefeat Colonel Windshear with your team dying no more than 15 times"; +$Boss::ProficiencyCode["CnlWindshear", 0] = "$TWM2::BossManager.bossKills < 15"; +$Boss::Proficiency["CnlWindshear", 1] = "Team Silver\t5000\tDefeat Colonel Windshear with your team dying no more than 10 times"; +$Boss::ProficiencyCode["CnlWindshear", 1] = "$TWM2::BossManager.bossKills < 10"; +$Boss::Proficiency["CnlWindshear", 2] = "Team Gold\t10000\tDefeat Colonel Windshear with your team dying no more than 5 times"; +$Boss::ProficiencyCode["CnlWindshear", 2] = "$TWM2::BossManager.bossKills < 5"; + //This sets up the drone and the functions needed to start the drone. function StartWindshear(%pos){ %team = 6; %rotation = "1 0 0 0"; %skill = 10; - %Drone = new FlyingVehicle() { + %drone = new FlyingVehicle() { dataBlock = WindshearPlatform; position = %pos; rotation = %rotation; team = %team; }; - MissionCleanUp.add(%Drone); + MissionCleanUp.add(%drone); - setTargetSensorGroup(%Drone.getTarget(), %team); + setTargetSensorGroup(%drone.getTarget(), %team); - %Drone.isdrone = 1; + %drone.isdrone = 1; %drone.dodgeGround = 0; %drone.isace = 1; @@ -27,11 +34,22 @@ function StartWindshear(%pos){ InitiateBoss(%drone, "CnlWindshear"); + %drone.turretObject.team = %team; + setTargetSensorGroup(%drone.turretObject.getTarget(), %team); + %drone.turretObject2.team = %team; + setTargetSensorGroup(%drone.turretObject2.getTarget(), %team); + %drone.turretObject3.team = %team; + setTargetSensorGroup(%drone.turretObject3.getTarget(), %team); + %drone.turretObject4.team = %team; + setTargetSensorGroup(%drone.turretObject4.getTarget(), %team); + %drone.turretObject5.team = %team; + setTargetSensorGroup(%drone.turretObject5.getTarget(), %team); + //Helpers - %pos2 = vectoradd(%pos, "15 0 0"); - %pos3 = vectoradd(%pos, "-15 0 0"); - %d2 = StartAIGunship(%pos2, "", 6, "ace", 0); - %d3 = StartAIGunship(%pos3, "", 6, "ace", 0); + %pos2 = vectoradd(%pos, "50 0 0"); + %pos3 = vectoradd(%pos, "-50 0 0"); + %d2 = StartAIGunship(%pos2, "0 0 0 1", %team, "ace", 0); + %d3 = StartAIGunship(%pos3, "0 0 0 1", %team, "ace", 0); %d2.isUltrally = 1; %d3.isUltrally = 1; // diff --git a/scripts/TWM2/Bosses/GeneralVegenor.cs b/scripts/TWM2/Bosses/GeneralVegenor.cs index 0128656..134455b 100644 --- a/scripts/TWM2/Bosses/GeneralVegenor.cs +++ b/scripts/TWM2/Bosses/GeneralVegenor.cs @@ -263,7 +263,7 @@ function VegenorAttack_FUNC(%att, %args) { //schedule the next one schedule(30000, 0, "VegenorAttack_FUNC", "Summon", %z); //-------------------- - %type = getRandomZombieType("1 2 3 4 5 9 12 13 14"); + %type = TWM2Lib_Zombie_Core("getRandomZombieType", "1 2 3 4 5 9 12 13 14"); %msg = getrandom(1,2); switch(%msg) { case 1: @@ -274,10 +274,10 @@ function VegenorAttack_FUNC(%att, %args) { for(%i = 0; %i < 6; %i++) { %pos = vectoradd(%z.getPosition(), TWM2Lib_MainControl("getRandomPosition", 10 TAB 1)); %fpos = vectoradd("0 0 5",%pos); - StartAZombie(%fpos, %type); + TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", %type, %fpos) } %z.setMoveState(true); - %z.setActionThread($Zombie::RAAMThread, true); + %z.setActionThread($Zombie::RogThread, true); %z.schedule(3500, "setMoveState", false); case "SetFire": %t = getWord(%args, 0); diff --git a/scripts/TWM2/Bosses/LordRog.cs b/scripts/TWM2/Bosses/LordRog.cs index 3a4a9e0..664303c 100644 --- a/scripts/TWM2/Bosses/LordRog.cs +++ b/scripts/TWM2/Bosses/LordRog.cs @@ -342,15 +342,15 @@ function LordRogAttack_FUNC(%att, %args) { } schedule(30000, 0, LordRogAttack_FUNC, "ZombieSummon", %z); //-------------------- - %type = getRandomZombieType("1 2 3 4 5 9 12 13 15"); + %type = TWM2Lib_Zombie_Core("getRandomZombieType", "1 2 3 4 5 9 12 13 15"); messageall('RogMsg',"\c4"@$TWM2::ZombieName[8]@": Attack my target!"); for(%i = 0; %i < 5; %i++) { %pos = vectoradd(%z.getPosition(), TWM2Lib_MainControl("getRandomPosition", 10 TAB 1)); %fpos = vectoradd("0 0 5",%pos); - StartAZombie(%fpos, %type); + TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", %type, %fpos); } %z.setMoveState(true); - %z.setActionThread($Zombie::RAAMThread, true); + %z.setActionThread($Zombie::RogThread, true); %z.schedule(3500, "setMoveState", false); case "DropshipReinforce": @@ -359,7 +359,7 @@ function LordRogAttack_FUNC(%att, %args) { return; } - %type = getRandomZombieType("1 2 3 4 5 9 12 13 15"); + %type = TWM2Lib_Zombie_Core("getRandomZombieType", "1 2 3 4 5 9 12 13 15"); MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[8]@": Additional Reinforcements!!! NOW!"); %typeCaller = %type SPC %type SPC %type SPC %type; %callPos = vectorAdd(%z.getPosition(), "2000 0 400"); diff --git a/scripts/TWM2/Bosses/LordVardison.cs b/scripts/TWM2/Bosses/LordVardison.cs index d99d000..653b326 100644 --- a/scripts/TWM2/Bosses/LordVardison.cs +++ b/scripts/TWM2/Bosses/LordVardison.cs @@ -23,6 +23,19 @@ // - Shadow Orb at all Phases // - Shadow Orb regenerates Vardison's HP +$Boss::Proficiency["Vardison3", 0] = "Team Bronze\t1000\tDefeat Lord Vardison with your team dying no more than 25 times"; +$Boss::ProficiencyCode["Vardison3", 0] = "$TWM2::BossManager.bossKills < 25"; +$Boss::Proficiency["Vardison3", 1] = "Team Silver\t5000\tDefeat Lord Vardison with your team dying no more than 15 times"; +$Boss::ProficiencyCode["Vardison3", 1] = "$TWM2::BossManager.bossKills < 15"; +$Boss::Proficiency["Vardison3", 2] = "Team Gold\t10000\tDefeat Lord Vardison with your team dying no more than 10 times"; +$Boss::ProficiencyCode["Vardison3", 2] = "$TWM2::BossManager.bossKills < 10"; +$Boss::Proficiency["Vardison3", 3] = "Demon Slayer\t25000\tDefeat Lord Vardison's Third Phase without dying, and dealing more than 15% damage to him"; +$Boss::ProficiencyCode["Vardison3", 3] = "[bProf].bossDeaths == 0 && [dPerc] > 15"; +$Boss::Proficiency["Vardison3", 4] = "Shadow Disconnect\t10000\tDeny Lord Vardison all Shadow Orb detonations"; +$Boss::ProficiencyCode["Vardison3", 4] = "$TWM2::VardisonDifficulty >= 2 && [bProf].orbDetonates == 0"; +$Boss::Proficiency["Vardison3", 5] = "The Unholy One\t75000\tDefeat Lord Vardison's Third Phase without dying, and dealing more than 15% damage to him on WTF difficulty"; +$Boss::ProficiencyCode["Vardison3", 5] = "$TWM2::VardisonDifficulty == 4 && [bProf].bossDeaths == 0 && [dPerc] > 15"; + $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?"; @@ -1031,7 +1044,7 @@ function VardisonDoMinionSummon(%Boss) { } function SpawnVMinion(%position) { - %minion = StartAZombie(%position, 17); + %minion = TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", 17, %position); if(isObject(%minion)) { //Apply minion settings & increase count $TWM2::VardisonManager.minionCount++; @@ -1683,6 +1696,7 @@ function VardisonManager::orbKill(%this, %boss, %orb) { %restoreCount = 0; for(%i = 0; %i < ClientGroup.getCount(); %i++) { %cl = ClientGroup.getObject(%i); + %cl.bossProficiency.orbDetonates++; if(isObject(%cl.player) && %cl.player.getState() !$= "dead") { //Bye Bye :) %cl.player.rapierShield = false; @@ -1697,7 +1711,9 @@ function VardisonManager::orbKill(%this, %boss, %orb) { } } } - MessageAll('msgRestore', "\c5Lord Vardison has absorbed the life energy of "@%restoreCount@" combatants."); + if($TWM2::Vardison_OrbRegenHP[$TWM2::VardisonDifficulty]) { + MessageAll('msgRestore', "\c5Lord Vardison has absorbed the life energy of "@%restoreCount@" combatants."); + } %wipeEmit = new ParticleEmissionDummy(){ position = %orb.getPosition(); dataBlock = "defaultEmissionDummy"; diff --git a/scripts/TWM2/Bosses/LordYvex.cs b/scripts/TWM2/Bosses/LordYvex.cs index 788e5be..8b3fd2d 100644 --- a/scripts/TWM2/Bosses/LordYvex.cs +++ b/scripts/TWM2/Bosses/LordYvex.cs @@ -1,3 +1,26 @@ +//LordYvex.cs +//Phantom139 +//TWM2 + +//Contains all of the datablocks and functioning for the Lord Yvex boss + +$Boss::Proficiency["Yvex", 0] = "Team Bronze\t1000\tDefeat Lord Yvex with your team dying no more than 25 times"; +$Boss::ProficiencyCode["Yvex", 0] = "$TWM2::BossManager.bossKills < 25"; +$Boss::Proficiency["Yvex", 1] = "Team Silver\t5000\tDefeat Lord Yvex with your team dying no more than 15 times"; +$Boss::ProficiencyCode["Yvex", 1] = "$TWM2::BossManager.bossKills < 15"; +$Boss::Proficiency["Yvex", 2] = "Team Gold\t10000\tDefeat Lord Yvex with your team dying no more than 10 times"; +$Boss::ProficiencyCode["Yvex", 2] = "$TWM2::BossManager.bossKills < 10"; +$Boss::Proficiency["Yvex", 3] = "Foolproof\t25000\tDefeat Lord Yvex without being killed by his Marvolic Pulse attack"; +$Boss::ProficiencyCode["Yvex", 3] = "[bProf].pulseDeaths == 0"; +$Boss::Proficiency["Yvex", 4] = "I'll Stick With Bullets\t10000\tDefeat Lord Yvex without using the Aegis of Dawn"; +$Boss::ProficiencyCode["Yvex", 4] = "[bProf].aegisUses == 0"; +$Boss::Proficiency["Yvex", 5] = "Sleepless\t25000\tDefeat Lord Yvex without falling victim to his nightmare once"; +$Boss::ProficiencyCode["Yvex", 5] = "[bProf].totalNightmareTicks == 0"; + +//TWM2 3.9.2: Boss Scaling Factor +$Boss::DamageScaling["Yvex"] = 5.0; +$Boss::ScaleReduction["Yvex"] = 0.15; + //DATABLOCKS datablock ParticleData(InflictionNightmareGlobeSmoke) { dragCoefficient = 50;/////////----------------------- @@ -672,7 +695,7 @@ function YvexAttack_FUNC(%att, %args) { //schedule the next one schedule(40000, 0, "YvexAttack_FUNC", "ZombieSummon", %z); //-------------------- - %type = getRandomZombieType("1 2 3 4 5 9 12 13"); + %type = TWM2Lib_Zombie_Core("getRandomZombieType", "1 2 3 4 5 9 12 13"); %msg = getrandom(1, 3); switch(%msg) { case 1: @@ -685,10 +708,10 @@ function YvexAttack_FUNC(%att, %args) { for(%i = 0; %i < 5; %i++) { %pos = vectoradd(%z.getPosition(), TWM2Lib_MainControl("getRandomPosition", 10 TAB 1)); %fpos = vectoradd("0 0 5",%pos); - StartAZombie(%fpos, %type); + TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", %type, %fpos); } %z.setMoveState(true); - %z.setActionThread($Zombie::RAAMThread, true); + %z.setActionThread($Zombie::RogThread, true); %z.schedule(3500, "setMoveState", false); case "FireCurse": @@ -862,6 +885,8 @@ function Yvexnightmareloop(%zombie,%viewer) { %viewer.player.setActionThread(%emote,true); %viewer.player.setWhiteout(0.8); %viewer.player.setDamageFlash(0.5); + + %viewer.bossProficiency.totalNightmareTicks++; %zombie.playShieldEffect("1 1 1"); serverPlay3D(NightmareScreamSound, %viewer.player.position); @@ -891,6 +916,8 @@ function KillerPulse::onCollision(%data,%projectile,%targetObject,%modifier,%pos %targetObject.throwWeapon(); %targetObject.clearinventory(); YvexAttack_FUNC("KillLoop", %targetObject); + + %targetObject.client.bossProficiency.pulseDeaths++; } } @@ -900,7 +927,7 @@ function YvexZombieMakerMissile::OnExplode(%data, %proj, %pos, %mod) { %c.schedule(%rand * 750, "delete"); for(%i = 0; %i < %rand; %i++) { %time = %i * 750; - %type = getRandomZombieType("1 2 3 4 5 9 12 13"); - schedule(%time, 0, "StartAZombie", vectoradd(%pos, "0 0 1"), %type); + %type = TWM2Lib_Zombie_Core("getRandomZombieType", "1 2 3 4 5 9 12 13"); + schedule(%time, 0, "TWM2Lib_Zombie_Core", "SpawnZombie", "zSpawnCommand", %type, vectorAdd(%pos, "0 0 1")); } } diff --git a/scripts/TWM2/Bosses/MajorInsignia.cs b/scripts/TWM2/Bosses/MajorInsignia.cs index 4b7b5f8..c36ee8e 100644 --- a/scripts/TWM2/Bosses/MajorInsignia.cs +++ b/scripts/TWM2/Bosses/MajorInsignia.cs @@ -256,20 +256,20 @@ function InsigniaAttack_FUNC(%att, %args) { } schedule(30000, 0, InsigniaAttack_FUNC, "ZombieSummon", %z); //-------------------- - %type = getRandomZombieType("1 2 3 5 9 12 13 15 17"); //omit 4 in place of 17: Demon -> Elite Demon + %type = TWM2Lib_Zombie_Core("getRandomZombieType", "1 2 3 5 9 12 13 15 17"); //omit 4 in place of 17: Demon -> Elite Demon messageall('RogMsg',"\c4"@$TWM2::BossName["Insignia"]@": Slay the humans!!!"); for(%i = 0; %i < 6; %i++) { %pos = vectoradd(%z.getPosition(), TWM2Lib_MainControl("getRandomPosition", 10 TAB 1)); %fpos = vectoradd("0 0 5",%pos); - StartAZombie(%fpos, %type); + TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", %type, %fpos); } %z.setMoveState(true); - %z.setActionThread($Zombie::RAAMThread, true); + %z.setActionThread($Zombie::RogThread, true); %z.schedule(3500, "setMoveState", false); case "Reinforce": %zombie = getWord(%args, 0); - %type = getRandomZombieType("1 2 3 5 9 12 13 15 17"); + %type = TWM2Lib_Zombie_Core("getRandomZombieType", "1 2 3 5 9 12 13 15 17"); MessageAll('MessageAll', "\c4"@$TWM2::BossName["Insignia"]@": It's time for you to take on my reinforcements!"); %typeCaller = %type SPC %type SPC %type SPC %type; %callPos1 = vectorAdd(%zombie.getPosition(), "2000 100 400"); diff --git a/scripts/TWM2/Bosses/ShadeLord.cs b/scripts/TWM2/Bosses/ShadeLord.cs index a1d4c69..346bfa8 100644 --- a/scripts/TWM2/Bosses/ShadeLord.cs +++ b/scripts/TWM2/Bosses/ShadeLord.cs @@ -10,6 +10,8 @@ $Boss::Proficiency["ShadeLord", 4] = "Smite the Shadows\t50000\tDefeat the Shade $Boss::ProficiencyCode["ShadeLord", 4] = "$TWM2::BossManager.bossKills == 0"; $Boss::Proficiency["ShadeLord", 5] = "Shade Buster\t7500\tDefeat the Shade Lord without dying once by the elemental shade"; $Boss::ProficiencyCode["ShadeLord", 5] = "[bProf].shadeDeaths == 0"; +$Boss::Proficiency["ShadeLord", 6] = "Invisible\t15000\tDefeat the Shade Lord without being targeted once by shade drops"; +$Boss::ProficiencyCode["ShadeLord", 6] = "[bProf].shadeTargets == 0"; //SHADE LORD datablock ParticleData(ShadeSwordParticle) { @@ -124,6 +126,8 @@ function ShadeLordSword::OnExplode(%data, %proj, %pos, %mod) { %potentialTarget.setMoveState(true); %potentialTarget.setActionThread("death1", true); createBlood(%potentialTarget); + + %potentialTarget.client.bossProficiency.shadeDeaths++; //=========================== schedule(750, 0, createBlood, %potentialTarget); schedule(1250, 0, createBlood, %potentialTarget); @@ -842,6 +846,7 @@ function ShadeLordFunction(%boss, %function, %args) { if(%closestDistance <= $Zombie::detectDist) { if(%closestDistance < 10) { ShadeLordFunction(%boss, "ShadeLordDropKill", %closestClient); + %closestClient.client.bossProficiency.shadeTargets++; MessageAll('MsgVardison', "\c4"@$TWM2::BossName["ShadeLord"]@": Feel The Vengeance of the Shadows "@getTaggedString(%closestClient.client.name)@"."); //%closestClient.setMoveState(true); ShadeLordFunction(%boss, "ShadeLordRandomTeleport", ""); diff --git a/scripts/TWM2/ChatCommands/Admin.cs b/scripts/TWM2/ChatCommands/Admin.cs index 9f4129f..a30c04b 100644 --- a/scripts/TWM2/ChatCommands/Admin.cs +++ b/scripts/TWM2/ChatCommands/Admin.cs @@ -819,7 +819,7 @@ function parseAdminCommands(%sender, %command, %args) { messageall('MsgAdminForce', "\c3"@%sender.namebase@"\c2 "@%message@"."); for(%i = 0; %i < %amount; %i++) { %time = %i * 500; - schedule(%time, 0, StartAZombie, %Fpos, %var); + schedule(%time, 0, "TWM2Lib_Zombie_Core", "SpawnZombie", "zSpawnCommand", %var, %Fpos); } return 1; @@ -877,7 +877,7 @@ function parseAdminCommands(%sender, %command, %args) { %targetlastpos = %target.player.getworldboxcenter(); makePersonHumanFZomb(%targetlastpos, %target); } - CureInfection(%target.player); + TWM2Lib_Zombie_Core("cureInfection", %target.player); messageall('MsgAdminForce', "\c3"@ %sender.namebase@"\c2 Cured \c3"@%target.namebase@"'s\c2 Infection."); messageclient(%target, 'MsgClient', "\c5Your Infection Has Been Cured"); return 1; diff --git a/scripts/TWM2/ChatCommands/Public.cs b/scripts/TWM2/ChatCommands/Public.cs index 113216e..b847cae 100644 --- a/scripts/TWM2/ChatCommands/Public.cs +++ b/scripts/TWM2/ChatCommands/Public.cs @@ -876,6 +876,10 @@ function parsePublicCommands(%sender, %command, %args) { messageclient(%sender, 'MsgClient', '\c2The server host has disabled boss votes.'); return 1; } + if($Host::LivingWorldMode == 1) { + messageclient(%sender, 'MsgClient', '\c2Boss voting is disabled in Living World Mode.'); + return 1; + } if($TWM::PlayingHorde || $TWM::PlayingHelljump) { messageclient(%sender, 'MsgClient', '\c2No bosses allowed in horde or helljump.'); return 1; diff --git a/scripts/TWM2/ChatCommands/SuperAdmin.cs b/scripts/TWM2/ChatCommands/SuperAdmin.cs index 727173e..952d7f0 100644 --- a/scripts/TWM2/ChatCommands/SuperAdmin.cs +++ b/scripts/TWM2/ChatCommands/SuperAdmin.cs @@ -83,6 +83,10 @@ function parseSuperAdminCommands(%sender, %command, %args) { if (!%sender.issuperadmin){ return 3; } + if($Host::LivingWorldMode == 1) { + messageClient(%sender, 'MsgClient', '\c2Cannot spawn bosses in living world mode'); + return 1; + } if($TWM::PlayingHellJump || $TWM::PlayingHorde) { messageClient(%sender, 'MsgClient', '\c2Cannot spawn bosses in horde or helljump'); return 1; diff --git a/scripts/TWM2/LoadMod.cs b/scripts/TWM2/LoadMod.cs index afb54d2..cf73c6b 100644 --- a/scripts/TWM2/LoadMod.cs +++ b/scripts/TWM2/LoadMod.cs @@ -11,6 +11,7 @@ exec("serverControl.cs"); //Server Settings exec("scripts/TWM2/Systems/Directorate.cs"); //Client Container Objects exec("scripts/TWM2/Systems/AdvancedRankSystem.cs"); //Adv. Ranks exec("scripts/TWM2/Systems/MainControl.cs"); //TWM2 Core Functions +exec("scripts/TWM2/Systems/LivingWorldMode.cs"); //Living World Mode (Construction 2.0) exec("scripts/TWM2/Systems/ObjectDamage.cs"); //Object Damage Functioning exec("scripts/TWM2/Systems/Scoremenucmds.cs"); //Score Menu exec("scripts/TWM2/Systems/BossSystem.cs"); //Bosses diff --git a/scripts/TWM2/Missions/Invasion.cs b/scripts/TWM2/Missions/Invasion.cs index 1741ddd..63620d3 100644 --- a/scripts/TWM2/Missions/Invasion.cs +++ b/scripts/TWM2/Missions/Invasion.cs @@ -1,101 +1,101 @@ package TWM2Mission_Invasion { - function TWM2MissionClass::initiateSettings(%group) { - %group.commandName = "Command"; - %group.failMessage = "Your squad has been eliminated, mission failed"; - %group.BonusCompleteMessage = "Excellent work soldiers, You've held back a major storm!"; - %group.CompleteMessageNoTime = "All enemy dropships neutralized, good work team."; - %group.bonusEXP = 2500; - %group.completionEXP = 2000; - } + function TWM2MissionClass::initiateSettings(%group) { + %group.commandName = "Command"; + %group.failMessage = "Your squad has been eliminated, mission failed"; + %group.BonusCompleteMessage = "Excellent work soldiers, You've held back a major storm!"; + %group.CompleteMessageNoTime = "All enemy dropships neutralized, good work team."; + %group.bonusEXP = 2500; + %group.completionEXP = 2000; + } - function TWM2MissionClass::OnTimeZero(%group) { - %group.MessageMissionGroup("\c5"@%group.commandName@": Enemy dropships have been eliminated, good work team!"); - for(%i = 1; %i <= %group.participants; %i++) { - %spF = game.pickPlayerSpawn( %group.participant[%i], false ); - %group.participant[%i].player.setPosition(%spF); - - AwardClient(%group.participant[%i], 37); - - CompleteNWChallenge(%group.participant[%i], "InvasionBuster"); - } - %group.AddMissionTime(10); //surviving = success with reward - %group.CompleteMission(); - } + function TWM2MissionClass::OnTimeZero(%group) { + %group.MessageMissionGroup("\c5"@%group.commandName@": Enemy dropships have been eliminated, good work team!"); + for(%i = 1; %i <= %group.participants; %i++) { + %spF = game.pickPlayerSpawn( %group.participant[%i], false ); + %group.participant[%i].player.setPosition(%spF); - function TWM2MissionClass::StartTWM2Mis(%group) { - %sp = "19528 17981 105"; - for(%i = 1; %i <= %group.participants; %i++) { - %spF = vectorAdd(%sp, TWM2Lib_MainControl("getRandomPosition", 5 TAB 1)); - %group.participant[%i].player.setPosition(%spF); - // - %player = %group.participant[%i].player; - %player.setArmor("Medium"); //commando! - %player.clearInventory(); - %player.setInventory(S3SRifle, 1, true); - %player.setInventory(S3SRifleAmmo, 30, true); - %player.ClipCount[S3SRifleImage.ClipName] = mfloor(S3SRifleImage.InitialClips * 1.5); - %player.setInventory(Mp26CMDO, 1, true); - %player.setInventory(Mp26CMDOAmmo, 50, true); - %player.ClipCount[Mp26CMDOImage.ClipName] = mfloor(Mp26CMDOImage.InitialClips * 1.5); - %player.setInventory(pistol, 1, true); - %player.setInventory(pistolAmmo, 10, true); - %player.ClipCount[pistolImage.ClipName] = pistolImage.InitialClips; - %player.setInventory(TargetingLaser, 1, true); - %player.setInventory(RepairKit,3); - %player.setInventory(Grenade,5); - %player.use(S3Rifle); - } - // - spawnDropshipWave(%group, %sp); - schedule(30000, 0, spawnDropshipWave, %group, %sp); - schedule(60000, 0, spawnDropshipWave, %group, %sp); - schedule(90000, 0, spawnDropshipWave, %group, %sp); - schedule(120000, 0, spawnDropshipWave, %group, %sp); - schedule(150000, 0, spawnDropshipWave, %group, %sp); - schedule(180000, 0, spawnDropshipWave, %group, %sp); - schedule(190000, 0, spawnDropshipWave, %group, %sp); - } + AwardClient(%group.participant[%i], 37); - function spawnHunterDropship_Mission(%position, %dropPosition, %dropType) { - %dropT = %dropType SPC %dropType SPC %dropType SPC %dropType; - //spawn dropship - %drop = new FlyingVehicle() { - dataBlock = "HunterDropship"; - position = %position; - respawn = "0"; - teamBought = 30; - team = 30; - }; - MissionCleanup.add(%drop); - //attach waypoint, spawn pilot/passengers - %wraith = StartAZombie(vectorAdd(%position, "0 0 100"), 15); - %wraith.isInTheMission = 1; - %drop.mountObject(%wraith, 0); - for(%i = 0; %i < getWordCount(%dropT); %i++) { - %z = StartAZombie(vectorAdd(%position, "0 0 100"), getWord(%dropT, %i)); - %z.isInTheMission = 1; - if(isObject(%z)) { - %drop.mountObject(%z, %i+2); - //%z.mountObject(%drop, %i+2); - } - } - dropshipMarkerLoop(%drop); - //engage dropship AI - BeginDropshipAI(%drop, %dropPosition); - } + CompleteNWChallenge(%group.participant[%i], "InvasionBuster"); + } + %group.AddMissionTime(10); //surviving = success with reward + %group.CompleteMission(); + } - function spawnDropshipWave(%group, %start) { - if(!isObject(%group)) { - return; - } - %pos[0] = vectorAdd(%start, "2000 0 400"); - %pos[1] = vectorAdd(%start, "-2000 0 400"); - %pos[2] = vectorAdd(%start, "0 2000 400"); - %pos[3] = vectorAdd(%start, "0 -2000 400"); - - spawnHunterDropship_Mission(%pos[0], %start, 1); - schedule(2500, 0, "spawnHunterDropship_Mission", %pos[1], %start, 1); - schedule(5000, 0, "spawnHunterDropship_Mission", %pos[2], %start, 1); - schedule(7500, 0, "spawnHunterDropship_Mission", %pos[3], %start, 1); - } + function TWM2MissionClass::StartTWM2Mis(%group) { + %sp = "19528 17981 105"; + for(%i = 1; %i <= %group.participants; %i++) { + %spF = vectorAdd(%sp, TWM2Lib_MainControl("getRandomPosition", 5 TAB 1)); + %group.participant[%i].player.setPosition(%spF); + // + %player = %group.participant[%i].player; + %player.setArmor("Medium"); //commando! + %player.clearInventory(); + %player.setInventory(S3SRifle, 1, true); + %player.setInventory(S3SRifleAmmo, 30, true); + %player.ClipCount[S3SRifleImage.ClipName] = mfloor(S3SRifleImage.InitialClips * 1.5); + %player.setInventory(Mp26CMDO, 1, true); + %player.setInventory(Mp26CMDOAmmo, 50, true); + %player.ClipCount[Mp26CMDOImage.ClipName] = mfloor(Mp26CMDOImage.InitialClips * 1.5); + %player.setInventory(pistol, 1, true); + %player.setInventory(pistolAmmo, 10, true); + %player.ClipCount[pistolImage.ClipName] = pistolImage.InitialClips; + %player.setInventory(TargetingLaser, 1, true); + %player.setInventory(RepairKit,3); + %player.setInventory(Grenade,5); + %player.use(S3Rifle); + } + // + spawnDropshipWave(%group, %sp); + schedule(30000, 0, spawnDropshipWave, %group, %sp); + schedule(60000, 0, spawnDropshipWave, %group, %sp); + schedule(90000, 0, spawnDropshipWave, %group, %sp); + schedule(120000, 0, spawnDropshipWave, %group, %sp); + schedule(150000, 0, spawnDropshipWave, %group, %sp); + schedule(180000, 0, spawnDropshipWave, %group, %sp); + schedule(190000, 0, spawnDropshipWave, %group, %sp); + } + + function spawnHunterDropship_Mission(%position, %dropPosition, %dropType) { + %dropT = %dropType SPC %dropType SPC %dropType SPC %dropType; + //spawn dropship + %drop = new FlyingVehicle() { + dataBlock = "HunterDropship"; + position = %position; + respawn = "0"; + teamBought = 30; + team = 30; + }; + MissionCleanup.add(%drop); + //attach waypoint, spawn pilot/passengers + %wraith = TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", 15, vectorAdd(%position, "0 0 100")); + %wraith.isInTheMission = 1; + %drop.mountObject(%wraith, 0); + for(%i = 0; %i < getWordCount(%dropT); %i++) { + %z = TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", getWord(%dropT, %i), vectorAdd(%position, "0 0 100")); + %z.isInTheMission = 1; + if(isObject(%z)) { + %drop.mountObject(%z, %i+2); + //%z.mountObject(%drop, %i+2); + } + } + dropshipMarkerLoop(%drop); + //engage dropship AI + BeginDropshipAI(%drop, %dropPosition); + } + + function spawnDropshipWave(%group, %start) { + if(!isObject(%group)) { + return; + } + %pos[0] = vectorAdd(%start, "2000 0 400"); + %pos[1] = vectorAdd(%start, "-2000 0 400"); + %pos[2] = vectorAdd(%start, "0 2000 400"); + %pos[3] = vectorAdd(%start, "0 -2000 400"); + + spawnHunterDropship_Mission(%pos[0], %start, 1); + schedule(2500, 0, "spawnHunterDropship_Mission", %pos[1], %start, 1); + schedule(5000, 0, "spawnHunterDropship_Mission", %pos[2], %start, 1); + schedule(7500, 0, "spawnHunterDropship_Mission", %pos[3], %start, 1); + } }; diff --git a/scripts/TWM2/Missions/RainDown.cs b/scripts/TWM2/Missions/RainDown.cs index 2d9ca0b..04cebe9 100644 --- a/scripts/TWM2/Missions/RainDown.cs +++ b/scripts/TWM2/Missions/RainDown.cs @@ -43,7 +43,7 @@ package TWM2Mission_RainDown { %missionPosCenter = "5400 12000 110"; for(%i = 0; %i < 15; %i++) { %posx = vectorAdd(%missionPosCenter, TWM2Lib_MainControl("getRandomPosition", 25 TAB 1)); - %zombie = StartAZombie(%posx, 1); + %zombie = TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", 1, %posx); %zombie.isInTheMission = 1; } RainDownMissionLoop(%group, MissionCleanup); diff --git a/scripts/TWM2/Systems/LivingWorldMode.cs b/scripts/TWM2/Systems/LivingWorldMode.cs new file mode 100644 index 0000000..1ea3882 --- /dev/null +++ b/scripts/TWM2/Systems/LivingWorldMode.cs @@ -0,0 +1,66 @@ +//LivingWorldMode.cs +//Phantom139 +//TWM2 3.9.2 +// Primary script control for the living world mode function + +// Living World Mode Details +// * Adds in-game events and enemy AI spawns outside of the need of an administrator to enable functioning +// - Enemy spawns are based upon player "activity", so a more active player will see more enemies near them +// - Conversely, inactive players will only see a few enemies here and there, and will usually be able to avoid combat if they want to +// - Enemy spawns will not occur near the map's main spawn point to prevent spawn camping +// * Boss Fights Disabled +// * Operations are still allowed + +// Living World Content +// * Threat Level: Indicates how much "action" is occuring, allows for more enemies and stronger enemies to spawn +// * Counter-Ops: Enemy forces will attempt to move into the region to secure assets or attack players, these public events are open to allowed +// * Boss Arena: When the Threat Level is maximized, hostile command elements will arrive, players can enter these zones to engage mini-boss enemies. + +function livingWorldOff() { + $Host::LivingWorldMode = 0; + LivingWorldLib_Function("DisableLivingWorld"); +} + +function livingWorldOn() { + $Host::LivingWorldMode = 1; + LivingWorldLib_Function("EnableLivingWorld"); +} + +function LivingWorldLib_Function(%functionName, %arg1, %arg2, %arg3, %arg4, %arg5) { + switch$(%functionName) { + //EnableLivingWorld(): No Arguments + // - Activate the script container instance responsible for storing information + case "EnableLivingWorld": + echo("LivingWorldLib_Function(): enable living world"); + if(isObject($TWM2::LivingWorldContainer)) { + $TWM2::LivingWorldContainer.delete(); + } + $TWM2::LivingWorldContainer = new ScriptObject() { + class = "LivingWorldContainer"; + threatLevel = 0; + instanceObjects = new SimGroup(LivingWorldInstanceObjects); + }; + + case "DisableLivingWorld": + echo("LivingWorldLib_Function(): disable living world"); + //Loop through the container, find and fade-delete all instance objects + %group = NameToID("LivingWorldInstanceObjects"); + for(%i = 0; %i < %group.getCount(); %i++) { + %obj = %group.getObject(%i); + if(%obj.isPlayer()) { + %obj.scriptKill(0); + %obj.startFade(200, 0, true); + %obj.schedule(205, delete); + } + else { + //Fade-Delete + %obj.startFade(500, 0, true); + %obj.schedule(505, delete); + } + } + %group.delete(); + if(isObject($TWM2::LivingWorldContainer)) { + $TWM2::LivingWorldContainer.delete(); + } + } +} \ No newline at end of file diff --git a/scripts/TWM2/Systems/MainControl.cs b/scripts/TWM2/Systems/MainControl.cs index 977c570..e9b5df3 100644 --- a/scripts/TWM2/Systems/MainControl.cs +++ b/scripts/TWM2/Systems/MainControl.cs @@ -1,6 +1,6 @@ //TWM2 Functions -$TWM2::Version = 3.91; -$TWM2::ModVersionString = "3.91 {Dev}"; +$TWM2::Version = 3.92; +$TWM2::ModVersionString = "3.92 {Dev}"; function TWM2Lib_MainControl(%functionName, %arguments) { switch$(strlwr(%functionName)) { @@ -481,21 +481,6 @@ function serverCmdCheckendTilt(%client) { } -function CureInfection(%player) { - if(%player.infected) { - %player.infected = 0; - if(isEventPending(%player.infectedDamage)) { - cancel(%player.infectedDamage); - %player.infectedDamage = ""; - %player.beats = 0; - %player.canZkill = 0; - cancel(%player.zombieAttackImpulse); - %player.setcancelimpulse = 1; - schedule(5000,0, "eval", ""@%player@".setcancelimpulse=0;"); //goodie - } - } -} - function DoMedalCheck(%client, %image) { // if(%client.isAIControlled()) { diff --git a/scripts/TWM2/Systems/ObjectDamage.cs b/scripts/TWM2/Systems/ObjectDamage.cs index 486093f..e3c0739 100644 --- a/scripts/TWM2/Systems/ObjectDamage.cs +++ b/scripts/TWM2/Systems/ObjectDamage.cs @@ -144,6 +144,26 @@ function CalculateProjectileDamage(%projectile, %target, %amount, %dType, %damLo } } + //Boss Scaling: TWM2 3.9.2 + // - This system scales fights to make it easier for smaller player counts in harder fights + if(%target.isBoss) { + %tName = $TWM2::BossManager.activeBoss; + if($Boss::DamageScaling[%tName]) { + %bossScale = $Boss::DamageScaling[%tName]; + + %playerCountReduction = ClientGroup.getCount() - 1; + %reduction = $Boss::ScaleReduction[%tName]; + + %net = %reduction * %playerCountReduction; + if(%net >= 1) { + %net = 1; + } + + %scale = %bossScale - (%bossScale * %net); + %total *= %scale; + } + } + %deal = %total * %amount; if(%target.isBoss) { if(%dType == $DamageType::SuperChaingun) { diff --git a/scripts/TWM2/Zombie/LoadZombieScripts.cs b/scripts/TWM2/Zombie/LoadZombieScripts.cs index a66b22c..2db8c6c 100644 --- a/scripts/TWM2/Zombie/LoadZombieScripts.cs +++ b/scripts/TWM2/Zombie/LoadZombieScripts.cs @@ -7,7 +7,6 @@ for($file = findFirstFile($search); $file !$= ""; $file = findNextFile($search)) exec("scripts/TWM2/Zombie/ZombieTypes/" @$type @ ".cs"); } -exec("scripts/TWM2/Zombie/ZombieCreation.cs"); -exec("scripts/TWM2/Zombie/MiscZombieFunctions.cs"); +exec("scripts/TWM2/Zombie/ZombieCore.cs"); exec("scripts/TWM2/Zombie/PlayerZombieFunctions.cs"); exec("scripts/TWM2/Zombie/PlayerZombieAttacks.cs"); diff --git a/scripts/TWM2/Zombie/PlayerZombieAttacks.cs b/scripts/TWM2/Zombie/PlayerZombieAttacks.cs index 11742f8..e01e467 100644 --- a/scripts/TWM2/Zombie/PlayerZombieAttacks.cs +++ b/scripts/TWM2/Zombie/PlayerZombieAttacks.cs @@ -283,7 +283,7 @@ function PlayerSummon(%player, %count) { for(%i = 0; %i < %count; %i++) { %pos = vectoradd(%player.getPosition(), TWM2Lib_MainControl("getRandomPosition", 10 TAB 1)); %fpos = vectoradd("0 0 5",%pos); - StartAZombie(%fpos, %type); + TWM2Lib_Zombie_Core("SpawnZombie", "zSpawnCommand", %type, %fpos); } %player.setMoveState(true); %player.setActionThread($Zombie::RogThread,true); diff --git a/scripts/TWM2/Zombie/ZombieCore.cs b/scripts/TWM2/Zombie/ZombieCore.cs new file mode 100644 index 0000000..d5f2133 --- /dev/null +++ b/scripts/TWM2/Zombie/ZombieCore.cs @@ -0,0 +1,570 @@ +//ZombieCore.cs +//TWM2 +// Dondelium_X, Phantom139 + +// Definitions that are common across all zombie types. +// For type specific functioning, please access the individual files in the ZombieTypes/ directory. + +// NOTE: Massive cleaning done as of TWM2 3.9.2 +// * GOALS: +// - Reduce Function Count +// - Smooth Zombie Movement +// - Simplify Zombie Logic + +//$Zombie::detectDist: The maximum distance in which a zombie may target a player +$Zombie::detectDist = 9999; +//$Zombie::FallDieHeight: The minimum altitude a zombie may be before being script killed +$Zombie::FallDieHeight = -500; + +//$Zombie::BaseSpeed: The default speed setting on zombies, any zombie that does not have a TypeSpeed var. set will default to the BaseSpeed +$Zombie::BaseSpeed = 150; +//$Zombie::TypeSpeed[#]: The speed of a specific zombie type instance, overrides BaseSpeed for that specific type +$Zombie::TypeSpeed[2] = 300; +$Zombie::TypeSpeed[3] = 800; +$Zombie::TypeSpeed[4] = 240; +$Zombie::TypeSpeed[5] = 300; + +//$Zombie::BaseJumpCooldown: The time zombies must elapse before jumping / lunging +$Zombie::BaseJumpCooldown = 1500; + +//$Zombie::SpeedMultiplier[#]: An additional multiplier to be applied to the zombie's base speed when calculating the impulse +$Zombie::SpeedMultiplier[2] = 0.6; +$Zombie::SpeedMultiplier[3] = 0.8; +$Zombie::SpeedMultiplier[4] = 0.75; + +//$Zombie::SpeedUpdateTime: How long (in ms) between each zombie update. The lower the number, the smoother the movement, but the more processing needed +$Zombie::SpeedUpdateTime = 100; + +//$Zombie::LungeDistance: How far (m) a zombie must be to lunge at a target +$Zombie::LungeDistance = 10; +//$Zombie::LordGrabDistance: How far (m) a zombie lord must be to grab a target +$Zombie::LordGrabDistance = 5; +//$Zombie::RapierUpwardScaling: How fast a rapier zombie will ascend when holding a player +$Zombie::RapierUpwardScaling = 750; + +//MISC Globals, Do not edit. +$Zombie::killpoints = 5; +$Zombie::RogThread = "cel1"; + +//**************************************************************************\\ +//**************************************************************************\\ +//**************************************************************************\\ +//**************************************************************************\\ +//**************************************************************************\\ +//************************ ZOMBIE CORE FUNCTIONING *************************\\ +//**************************************************************************\\ +//**************************************************************************\\ +//**************************************************************************\\ +//**************************************************************************\\ +//**************************************************************************\\ + +function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) { + switch$(strlwr(%functionName)) { + + //zsetrandommove(%zombie): Activated when the zombie needs to begin random movement + case "zsetrandommove": + if(!isObject(%arg1)) { + return; + } + %rx = getRandom(-10, 10); + %ry = getRandom(-10, 10); + %vec = %rx @ SPC @ %ry @ SPC @ 0; + %arg1.direction = vectorNormalize(%vec); + %arg1.Mnum = getRandom(1, 20); + %arg1.zombieRmove = schedule($Zombie::SpeedUpdateTime, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1); + + //zrandommoveloop(%zombie): Moves the zombies around in a random direction + case "zrandommoveloop": + if(!isObject(%arg1) || %arg1.getState() $= "dead") { + return; + } + if(%arg1.hasTarget) { + %arg1.direction = ""; + return; + } + if(%arg1.Mnum >= 1) { + %x = getWord(%arg1.direction, 1); + %y = getWord(%arg1.direction, 0) * -1; + %vec = %x @ SPC @ %y @ SPC @ 0; + %arg1.setRotation(fullrot("0 0 0", %vec)); + //Check for speed enhancement + %multiplier = $Zombie::SpeedMultiplier[%arg1.type] $= "" ? 1 : $Zombie::SpeedMultiplier[%arg1.type]; + %speed = %arg1.speed * %multiplier; + %vector = vectorScale(%vec, %speed); + %arg1.applyImpulse(%arg1.direction, %vector); + %arg1.Mnum -= 1; + %arg1.zombieRmove = schedule($Zombie::SpeedUpdateTime, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1); + } + else { + %arg1.zombieRmove = schedule($Zombie::SpeedUpdateTime, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1); + } + + //cureInfection(%player): Cures the zombie infection + case "cureinfection": + if(%arg1.infected) { + %arg1.infected = 0; + if(isEventPending(%arg1.infectedDamage)) { + cancel(%arg1.infectedDamage); + %arg1.infectedDamage = ""; + %arg1.beats = 0; + %arg1.canZkill = 0; + cancel(%arg1.zombieAttackImpulse); + %arg1.setcancelimpulse = 1; + schedule(5000,0, "eval", ""@%arg1@".setcancelimpulse=0;"); //goodie + } + } + + //infectloop(%player): Performs the infection loop. + case "infectloop": + //Check for flags that disable this. + if($TWM::PlayingHellJump || !$TWM::AllowZombieInfection) { + return; + } + if(!isObject(%arg1) || %arg1.getState() $= "dead" || %arg1.isGoingToDie) { + return; + } + if(%arg1.isBoss || !%arg1.infected) { + return; + } + //Additional checks... + if(%arg1.client !$= "") { + if(%arg1.client.isActivePerk("No-Infect Armor")) { + %arg1.playShieldEffect("1 1 1"); + %arg1.infected = 0; + return; + } + } + //Once we reach this point, we're good to go... + if(%arg1.beats $= "") { + TWM2Lib_Zombie_PlayerFunctions("zombieAttackImpulse", %arg1, 0); + } + + if(arg1.beats < 15) { + %arg1.setWhiteOut(%arg1.beats * 0.05); + } + else { + %arg1.setDamageFlash(1); + } + + if(%arg1.beats == 15) { + %arg1.canZKill = 1; + } + + if(%arg1.beats >= 15) { + serverPlay3D("ZombieMoan", %arg1.getWorldBoxCenter()); + } + else if(%arg1.beats >= 10) { + playDeathCry(%arg1); + } + else { + playPain(%arg1); + } + + if(%arg1.beats == 20) { + if($Host::canZombie $= "") { + $Host::canZombie = 0; + } + if($Host::canZombie) { + TWM2Lib_Zombie_PlayerFunctions("makePersonZombie", %arg1.client, %arg1.getTransform()); + } + else { + %arg1.damage(0, %arg1.getPosition(), 100.0, $DamageType::Zombie); + } + return; + } + %arg1.beats++; + %arg1.infectedDamage = schedule(2000, %arg1, "TWM2Lib_Zombie_Core", "infectLoop", %arg1); + + //setZFlag(%zombie, %flag, %value): Sets a flag value for a zombie + case "setzflag": + if(!isObject(%arg1)) { + return; + } + if(!isSet(%arg3)) { + %arg3 = 0; + } + switch$(strlwr(%arg2)): + case "canjump": + %arg1.canJump = %arg3; + case "recentshift": + %arg1.recentShift = %arg3; + + //lookForTarget(%zombie): Identify the closest target, and the distance to that target + case "lookfortarget": + if(!isObject(%arg1) || %arg1.getState() $= "dead") { + return; + } + %worldPos = %arg1.getWorldBoxCenter(); + %zPos = getWord(%worldPos, 2); + if(%zPos < $Zombie::FallDieHeight) { + %arg1.scriptKill(0); + return; + } + %clientCount = ClientGroup.getCount(); + %closestClient = -1; + %closestDistance = 999999; + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(isObject(%cl.player) && %cl.player.getState() !$= "dead" && TWM2Lib_Zombie_Core("ZombieTargetingAllowed", %arg1, %cl.player)) { + %vDist = vectorDist(%worldPos, %cl.player.getWorldBoxCenter()); + if(%vDist > 0 && %vDist < %closestDistance) { + %closestClient = %cl; + %closestDistance = %vDist; + } + } + } + return %closestClient SPC %closestDistance; + + //zombieTargetingAllowed(%zombie, %player): Verifies that the target player can be targeted by zombies + case "zombietargetingallowed": + //Object tests + if(!isObject(%arg1) || %arg1.getState() $= "dead") { + return false; + } + if(!isObject(%arg2) || %arg2.getState() $= "dead") { + return false; + } + //Flag Tests + if(%arg2.isFTD || %arg2.stealthed || %arg2.isBoss || %arg2.iszombie || %arg2.isGoingToDie || %arg2.inZombieSafeZone || %arg2.ignoredbyZombs) { + return false; + } + //NOTE: If you want to add additional targeting constraints, do so here. + return true; + + //zombieGetFacingDirection(%zombie, %player, %position): Fetch the direction the zombie needs to look at for a specific player target + case "zombiegetfacingdirection": + if(!isObject(%arg1) || %arg1.getState() $= "dead") { + return; + } + // + if(isObject(%arg2) && %arg2.getState !$= "dead") { + %tPos = %arg2.getPosition(); + } + else { + %tPos = TWM2Lib_MainControl("RMPG"); + } + // + %vec = vectorNormalize(vectorSub(%tPos, %arg3)); + %vx = getWord(%vector, 0) + %vy = getWord(%vector, 1) + %nvx = %vy + %nvy = (%vx * -1) + %lookVector = %nvx @ SPC @ %nvy @ SPC @ 0; + %arg1.setRotation(fullRot("0 0 0", %lookVector)); + + return %vec; + + //getrandomzombietype(%list): Fetch a random type of zombie from a given list + case "getrandomzombietype": + %select = getWord(%arg1, getRandom(0, getWordCount(%arg1))); + if(%select $= "") { + return 1; + } + return %select; + + //canspawnzombies(%source): Flag testing function to validate that a zombie is allowed to spawn + case "canspawnzombies": + if(strlwr(%arg1) $= "infectedplayer") { + if($Game::ZombieCount > $TWM2::MaxZombies || !$TWM2::CanSpawnZ || $TWM::PlayingInfection || $TWM::PlayingHorde || $TWM::PlayingHellJump) { + return false; + } + return true; + } + else if(strlwr(%arg1) $= "zpack") { + if($Game::ZombieCount > $TWM2::MaxZombies || !$TWM2::CanSpawnZ || $Host::LivingWorldMode) { + return false; + } + return true; + } + else if(strlwr(%arg1) $= "zspawncommand") { + if($Game::ZombieCount > $TWM2::MaxZombies || !$TWM2::CanSpawnZ || $Host::LivingWorldMode) { + return false; + } + return true; + } + else if(strlwr(%arg1) $= "forced") { + return true; + } + echo("TWM2Lib_Zombie_Core(canSpawnZombies): blocking zombie spawning, no source argument provided..."); + return false; + + //spawnZombie(%source, %type [%obj], %position) + case "spawnzombie": + if(!TWM2Lib_Zombie_Core("canSpawnZombies", %arg1)) { + return false; + } + //Fetch spawning parameters + switch$(strlwr(%arg1)) { + //infectedPlayer: Uses %obj as second argument, where %obj is the dead player + case "infectedplayer": + if(!isObject(%arg2)) { + return false; + } + %spawnPos = %arg2.getPosition(); + %spawnType = 1; + + //zPack: Uses %obj as the second argument, where %obj is the pack object + case "zpack": + if(!isObject(%arg2)) { + return false; + } + %spawnPos = vectorAdd(%arg2.getPosition(), "0 0 4"); + %spawnType = %arg2.ZType; + + //zSpawnCommand / forced: Uses %type and %position arguments + case "zspawncommand" or "forced": + %spawnPos = %arg3; + %spawnType = %arg2; + } + //Address parameters + if(%type $= "" || %type == 7 || %type == 8 || %type <= 0) { + %type = 1; + } + if(!isSet(%spawnPos)) { + echo("TWM2Lib_Zombie_Core(spawnZombie): Spawning position not specified, breaking."); + return false; + } + //Spawn the zombie. + switch(%spawnType) { + //Normal Zombie + case 1: + %zombie = new player() { + Datablock = "ZombieArmor"; + }; + if(Game.CheckModifier("YouCantSeeMe") == 1) { + %zombie.setCloaked(true); + } + + //Ravager Zombie + case 2: + %zombie = new player() { + Datablock = "RavagerZombieArmor"; + }; + + //Zombie Lord + case 3: + %zombie = new player() { + Datablock = "LordZombieArmor"; + }; + %zombie.client = $zombie::Lclient; + %zombie.mountImage(ZHead, 3); + %zombie.mountImage(ZBack, 4); + %zombie.mountImage(ZDummyslotImg, 5); + %zombie.mountImage(ZDummyslotImg2, 6); + %zombie.setInventory(AcidCannon, 1, true); + %zombie.use(AcidCannon); + %zombie.firstFired = 0; + %zombie.canmove = 1; + + //Demon Zombie + case 4: + %zombie = new player() { + Datablock = "DemonZombieArmor"; + }; + %zombie.mountImage(ZdummyslotImg, 4); + + //Air-Rapier Zombie + case 5: + %zombie = new player() { + Datablock = "RapierZombieArmor"; + }; + %zombie.mountImage(ZWingImage, 3); + %zombie.mountImage(ZWingImage2, 4); + %zombie.setActionThread("scoutRoot",true); + + //Demon Mother Zombie + case 6: + return DemonMotherCreate(%spawnPos); + + //Shifter Zombie + case 9: + %zombie = new player() { + Datablock = "ShifterZombieArmor"; + }; + + //Zombie Summoner + case 10: + %zombie = new player() { + Datablock = "SummonerZombieArmor"; + }; + + //Sniper Zombie + case 11: + %zombie = new player(){ + Datablock = "SniperZombieArmor"; + }; + %zombie.mountImage(ZSniperImage1, 4); + %zombie.mountImage(ZSniperImage2, 5); + + //Ultra-Demon Zombie + case 12: + %zombie = new player(){ + Datablock = "DemonUltraZombieArmor"; + }; + %zombie.NoHS = 1; + + //Volatile Ravager Zombie + case 13: + %zombie = new player(){ + Datablock = "VolatileRavagerZombieArmor"; + }; + %zombie.mountImage(ZExplosivePack, 4); + + //Sling-Shot Zombie + case 14: + %zombie = new player(){ + Datablock = "SSZombieArmor"; + }; + %zombie.mountImage(SSZombImage2, 4); + %zombie.mountImage(SSZombImage3, 5); + + //Wraith Zombie + case 15: + %zombie = new player(){ + Datablock = "WraithZombieArmor"; + }; + %zombie.setInventory(AcidCannon, 1, true); + %zombie.use(AcidCannon); + + //(Classic) General Rog + case 16: + %zombie = new player() { + Datablock = "ROGZombieArmor"; + }; + %zombie.NoHS = 1; + %zombie.isBoss = 1; + + %zombie.mountImage(ZdummyslotImg, 4); + %zombie.mountImage(ZMG42BaseImage, 5); + %zombie.mountImage(ROGSAWImage1, 6); + %zombie.mountImage(ROGSAWImage2, 7); + %zombie.mountImage(ROGSAWImage3, 8); + + %zombie.shotsfired = 0; + RapierShieldApply(%zombie); + + //Elite Demon (Vardison Minion) + case 17: + %zombie = new player(){ + Datablock = "EliteDemonZombieArmor"; + }; + %zombie.mountImage(ZdummyslotImg, 4); + } + //Verify that we spawned a zombie object, force spawn a normal zombie if we did not. + if(!isObject(%zombie)) { + echo("Zero zombie error, spawning normal"); + %spawnType = 1; + %zombie = new player(){ + Datablock = "ZombieArmor"; + }; + if(Game.CheckModifier("YouCantSeeMe") == 1) { + %zombie.setCloaked(true); + } + } + //Post spawn arguments + %zombie.team = 30; + %zname = $TWM2::ZombieName[%type]; // <- To Hosts, Enjoy, You can + //Change the Zombie Names now!!! + %zombie.target = createTarget(%zombie, %zname, "", "Derm3", '', %zombie.team, PlayerSensor); + setTargetSensorData(%zombie.target, PlayerSensor); + setTargetSensorGroup(%zombie.target, 30); + setTargetName(%zombie.target, addtaggedstring(%zname)); + setTargetSkin(%zombie.target, 'Horde'); + // + %zombie.type = %spawnType; + %zombie.setTransform(%spawnPos); + %zombie.canjump = 1; + %zombie.hastarget = 1; + %zombie.isZombie = 1; + ZombieGroup.add(%zombie); + + $Game::ZombieCount++; + + if(strlwr(%arg1) $= "zpack") { + if(%arg2.isInTheMission) { + %zombie.isInTheMission = 1; + } + %zombie.hasCP = 1; + if(%arg2.spawnTypeset == 1) { + %arg2.numZ = 3; + } + else { + %zombie.CP = %arg2; + } + } + + if(strlwr(%arg1) $= "infectedplayer") { + %zombie.zapObject(); + revivestand(%zombie, 0); + } + + if($Zombie::TypeSpeed[%spawnType] !$= "") { + %zombie.speed = $Zombie::TypeSpeed[%spawnType]; + } + else { + %zombie.speed = $Zombie::BaseSpeed; + } + + %zombie.getDatablock().AI(%zombie); + return %zombie; + } +} + +//************************************************************ +//*****************Zomb Attack Stuff************************** +//************************************************************ + +function ChargeEmitter(%zombie){ + if(!isobject(%zombie)) + return; + if(%zombie.chargecount >= 2){ + %charge2 = new ParticleEmissionDummy() + { + position = %zombie.getMuzzlePoint(6); + dataBlock = "defaultEmissionDummy"; + emitter = "burnEmitter"; + }; + MissionCleanup.add(%charge2); + %charge2.schedule(100, "delete"); + } + if(%zombie.chargecount <= 7){ + %charge = new ParticleEmissionDummy() + { + position = %zombie.getMuzzlePoint(5); + dataBlock = "defaultEmissionDummy"; + emitter = "burnEmitter"; + }; + MissionCleanup.add(%charge); + %charge.schedule(100, "delete"); + } + if(%zombie.chargecount <= 9){ + %zombie.Fire = schedule(100, %zombie, "ChargeEmitter", %zombie); + %zombie.chargecount++; + } + else + %zombie.chargecount = 0; +} + + +//----------------------------------------------------------- +//DEATH +datablock AudioProfile(ZombieDeathSound1) +{ + filename = "voice/Derm3/avo.deathcry_01.wav"; + description = AudioClose3d; + preload = true; +}; + +datablock AudioProfile(ZombieDeathSound2) +{ + filename = "voice/Derm2/avo.deathcry_01.wav"; + description = AudioClose3d; + preload = true; +}; + +datablock AudioProfile(ZombieDeathSound3) +{ + filename = "voice/Derm1/avo.deathcry_01.wav"; + description = AudioClose3d; + preload = true; +}; diff --git a/scripts/TWM2/Zombie/ZombieTypes/DemonLord.cs b/scripts/TWM2/Zombie/ZombieTypes/DemonLord.cs index 5b33124..47d39c8 100644 --- a/scripts/TWM2/Zombie/ZombieTypes/DemonLord.cs +++ b/scripts/TWM2/Zombie/ZombieTypes/DemonLord.cs @@ -584,7 +584,7 @@ function DemonMotherDemonSpawn(%obj){ }; MissionCleanup.add(%charge); %charge.schedule(1100, "delete"); - schedule(1000, 0, "startAzombie", posFromRaycast(%searchresult), 4); + schedule(1000, 0, "TWM2Lib_Zombie_Core", "SpawnZombie", "zSpawnCommand", 4, posFromRaycast(%searchResult)); } schedule(1500, 0, "DemonMotherThink", %obj); } diff --git a/scripts/TWM2/Zombie/ZombieTypes/Normal.cs b/scripts/TWM2/Zombie/ZombieTypes/Normal.cs index 5348f8b..31e2789 100644 --- a/scripts/TWM2/Zombie/ZombieTypes/Normal.cs +++ b/scripts/TWM2/Zombie/ZombieTypes/Normal.cs @@ -1,85 +1,91 @@ -datablock PlayerData(ZombieArmor) : LightMaleHumanArmor -{ - runForce = 60.20 * 90; - runEnergyDrain = 0.0; - minRunEnergy = 10; - maxForwardSpeed = 9; - maxBackwardSpeed = 7; - maxSideSpeed = 7; +datablock PlayerData(ZombieArmor) : LightMaleHumanArmor { + runForce = 60.20 * 90; + runEnergyDrain = 0.0; + minRunEnergy = 10; + maxForwardSpeed = 9; + maxBackwardSpeed = 7; + maxSideSpeed = 7; - jumpForce = 14.0 * 90; + jumpForce = 14.0 * 90; - maxDamage = 2.8; - minImpactSpeed = 35; - shapeFile = "bioderm_medium.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; + maxDamage = 2.8; + minImpactSpeed = 35; + shapeFile = "bioderm_medium.dts"; + jetEmitter = BiodermArmorJetEmitter; + jetEffect = BiodermArmorJetEffect; - debrisShapeName = "bio_player_debris.dts"; + debrisShapeName = "bio_player_debris.dts"; - //Foot Prints - decalData = LightBiodermFootprint; - decalOffset = 0.3; + //Foot Prints + decalData = LightBiodermFootprint; + decalOffset = 0.3; - waterBreathSound = WaterBreathBiodermSound; + waterBreathSound = WaterBreathBiodermSound; - damageScale[$DamageType::M1700] = 3.0; + damageScale[$DamageType::M1700] = 3.0; max[RepairKit] = 0; max[Mine] = 0; max[Grenade] = 0; }; -function Zombiemovetotarget(%zombie){ - if(!isobject(%Zombie)) - return; - if(%Zombie.getState() $= "dead") - return; - %pos = %zombie.getworldboxcenter(); - %closestClient = ZombieLookForTarget(%zombie); - %closestDistance = getWord(%closestClient,1); - %closestClient = getWord(%closestClient,0).Player; - if(%closestDistance <= $zombie::detectDist){ - if(%zombie.hastarget != 1){ - %zombie.hastarget = 1; - } - %chance = (getrandom() * 20); - if(%chance >= 19) { - %chance = (getRandom() * 12); - if(%chance <= 11) - serverPlay3d("ZombieMoan",%zombie.getWorldBoxCenter()); - else - serverPlay3d("ZombieHOWL",%zombie.getWorldBoxCenter()); - } - %vector = ZgetFacingDirection(%zombie,%closestClient,%pos); - - %fmultiplier = $Zombie::ForwardSpeed; - if(Game.CheckModifier("SuperLunge") == 1) { - %ld = $zombie::lungDist * 5; - } - else { - %ld = $zombie::lungDist; - } - if(%closestDistance <= %ld && %zombie.canjump == 1) - %fmultiplier = (%fmultiplier * 4); - %vector = vectorscale(%vector, %Fmultiplier); - %upvec = "150"; - if(%closestDistance <= %ld && %zombie.canjump == 1){ - %upvec = %upvec * 2; - %zombie.canjump = 0; - schedule(1500, %zombie, "Zsetjump", %zombie); - } - %x = Getword(%vector,0); - %y = Getword(%vector,1); - %z = Getword(%vector,2); - if(%z >= 600) - %upvec = (%upvec * 5); - %vector = %x@" "@%y@" "@%upvec; - %zombie.applyImpulse(%pos, %vector); - } - else if(%zombie.hastarget == 1){ - %zombie.hastarget = 0; - %zombie.zombieRmove = schedule(100, %zombie, "ZSetRandomMove", %zombie); - } - %zombie.moveloop = schedule(500, %zombie, "Zombiemovetotarget", %zombie); +function ZombieArmor::AI(%datablock, %zombie) { + //Normal zombies do not employ any "AI" other than target and move, fork off to main move function + %datablock.MoveToTarget(%zombie); +} + +function ZombieArmor::MoveToTarget(%datablock, %zombie) { + if(!isobject(%zombie) || %zombie.getState() $= "dead") { + return; + } + %pos = %zombie.getWorldBoxCenter(); + %closestClient = TWM2Lib_Zombie_Core("lookForTarget", %zombie); + %closestDistance = getWord(%closestClient, 1); + %closestClient = getWord(%closestClient, 0).Player; + if(%closestDistance <= $zombie::detectDist) { + if(%zombie.hastarget != 1) { + %zombie.hastarget = 1; + } + %chance = (getrandom() * 20); + if(%chance >= 19) { + %chance = (getRandom() * 12); + if(%chance <= 11) { + serverPlay3d("ZombieMoan", %zombie.getWorldBoxCenter()); + } + else { + serverPlay3d("ZombieHOWL", %zombie.getWorldBoxCenter()); + } + } + %vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %closestClient, %pos); + + if(Game.CheckModifier("SuperLunge") == 1) { + %ld = $Zombie::LungeDistance * 5; + } + else { + %ld = $Zombie::LungeDistance; + } + if(%closestDistance <= %ld && %zombie.canjump == 1) { + %vector = vectorScale(%vector, (%zombie.speed * 4)); + } + %vector = vectorScale(%vector, %zombie.speed); + %upvec = "150"; + if(%closestDistance <= %ld && %zombie.canjump == 1) { + %upvec *= 2; + TWM2Lib_Zombie_Core("setZFlag", %zombie, "canJump", 0); + schedule($Zombie::BaseJumpCooldown, 0, TWM2Lib_Zombie_Core, "setZFlag", %zombie, "canJump", 1); + } + %x = Getword(%vector, 0); + %y = Getword(%vector, 1); + %z = Getword(%vector, 2); + if(%z >= 600) { + %upvec = (%upvec * 5); + } + %vector = %x@" "@%y@" "@%upvec; + %zombie.applyImpulse(%pos, %vector); + } + else if(%zombie.hastarget == 1) { + %zombie.hastarget = 0; + %zombie.zombieRmove = schedule($Zombie::SpeedUpdateTime, %zombie, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %zombie); + } + %zombie.moveloop = %datablock.schedule($Zombie::SpeedUpdateTime, %datablock, "MoveToTarget", %zombie); } diff --git a/scripts/TWM2/Zombie/ZombieTypes/Ravager.cs b/scripts/TWM2/Zombie/ZombieTypes/Ravager.cs new file mode 100644 index 0000000..9a5a000 --- /dev/null +++ b/scripts/TWM2/Zombie/ZombieTypes/Ravager.cs @@ -0,0 +1,74 @@ +datablock PlayerData(RavagerZombieArmor) : LightMaleBiodermArmor +{ + maxDamage = 1.0; + minImpactSpeed = 50; + speedDamageScale = 0.015; + + damageScale[$DamageType::M1700] = 2.0; + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; +}; + +function FZombiemovetotarget(%zombie){ + if(!isobject(%Zombie)) + return; + if(%Zombie.getState() $= "dead") + return; + %pos = %zombie.getworldboxcenter(); + %closestClient = ZombieLookForTarget(%zombie); + %closestDistance = getWord(%closestClient,1); + %closestClient = getWord(%closestClient,0).Player; + if(%closestDistance <= $zombie::detectDist){ + if(%zombie.hastarget != 1){ + %zombie.hastarget = 1; + } + %zombie.setActionThread("scoutRoot",true); + %upvec = "250"; + %fmultiplier = $Zombie::FForwardSpeed; + + //moanStuff + %chance = (getrandom() * 50); + if(%chance >= 49) { + %chance = (getRandom() * 12); + if(%chance <= 11) + serverPlay3d("ZombieMoan",%zombie.getWorldBoxCenter()); + else + serverPlay3d("ZombieHOWL",%zombie.getWorldBoxCenter()); + } + + %vector = ZgetFacingDirection(%zombie,%closestClient,%pos); + + //Move Stuff + if(%closestDistance <= $zombie::lungDist && %zombie.canjump == 1 && getword(%vector, 2) <= "0.8" ){ + %zombie.setvelocity("0 0 0"); + %fmultiplier = (%fmultiplier * 2); + %upvec = (%upvec * 3.5); + %zombie.canjump = 0; + schedule(2000, %zombie, "Zsetjump", %zombie); + } + %vector = vectorscale(%vector, %Fmultiplier); + %x = Getword(%vector,0); + %y = Getword(%vector,1); + %z = Getword(%vector,2); + if(%z >= "1200" && %zombie.canjump == 1){ + %zombie.setvelocity("0 0 0"); + %upvec = (%upvec * 8); + %x = (%x * 0.5); + %y = (%y * 0.5); + %zombie.canjump = 0; + schedule(2500, %zombie, "Zsetjump", %zombie); + } + + %vector = %x@" "@%y@" "@%upvec; + %zombie.applyImpulse(%pos, %vector); + } + else if(%zombie.hastarget == 1){ + %zombie.hastarget = 0; + %zombie.zombieRmove = schedule(100, %zombie, "ZSetRandomMove", %zombie); + %zombie.setActionThread("ski",true); + } + %zombie.moveloop = schedule(500, %zombie, "FZombiemovetotarget", %zombie); +} + diff --git a/scripts/TWM2/Zombie/ZombieTypes/Shifter.cs b/scripts/TWM2/Zombie/ZombieTypes/Shifter.cs index 691f8a8..ec82bff 100644 --- a/scripts/TWM2/Zombie/ZombieTypes/Shifter.cs +++ b/scripts/TWM2/Zombie/ZombieTypes/Shifter.cs @@ -63,12 +63,13 @@ function ShifterZombiemovetotarget(%zombie){ //tis shift timez :) if(%closestDistance > 200 || (%zombie.getVelocity() == 0 && !%zombie.RecentShift)) { - %zombie.setVelocity("0 0 10"); - %zombie.startFade(500, 0, true); - %zombie.schedule(600, "SetPosition", VectorAdd(%closestClient.getPosition(), vectorAdd("0 0 3", TWM2Lib_MainControl("getRandomPosition", "5\t1")))); - %zombie.startFade(750, 0, false); + %zombie.setMoveState(true); + %zombie.startFade(1500, 0, true); + %zombie.schedule(1600, "SetPosition", VectorAdd(%closestClient.getPosition(), vectorAdd("0 0 3", TWM2Lib_MainControl("getRandomPosition", "5\t1")))); + %zombie.startFade(1750, 0, false); + %zombie.schedule(2000, setMoveState, false); %zombie.RecentShift = 1; - Schedule(3500, 0, "eval", ""@%zombie@".RecentShift=0;"); + Schedule(10500, 0, "eval", ""@%zombie@".RecentShift=0;"); } if(%closestDistance <= $zombie::lungDist && %zombie.canjump == 1){ diff --git a/scripts/TWM2/Zombie/ZombieTypes/Sniper.cs b/scripts/TWM2/Zombie/ZombieTypes/Sniper.cs index dc659b9..3e40882 100644 --- a/scripts/TWM2/Zombie/ZombieTypes/Sniper.cs +++ b/scripts/TWM2/Zombie/ZombieTypes/Sniper.cs @@ -1,3 +1,24 @@ +datablock PlayerData(SniperZombieArmor) : LightMaleHumanArmor { + boundingBox = "1.63 1.63 2.6"; + maxDamage = 2.5; + minImpactSpeed = 35; + shapeFile = "bioderm_heavy.dts"; + + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = HeavyBiodermFootprint; + decalOffset = 0.4; + + waterBreathSound = WaterBreathBiodermSound; + + damageScale[$DamageType::M1700] = 2.0; + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; +}; + datablock ShapeBaseImageData(ZSniperImage1) { shapeFile = "weapon_sniper.dts"; emap = true; diff --git a/scripts/TWM2/Zombie/ZombieTypes/Summoner.cs b/scripts/TWM2/Zombie/ZombieTypes/Summoner.cs index 50637c3..446ee16 100644 --- a/scripts/TWM2/Zombie/ZombieTypes/Summoner.cs +++ b/scripts/TWM2/Zombie/ZombieTypes/Summoner.cs @@ -71,7 +71,7 @@ function SummonerZombiemovetotarget(%zombie){ %c.schedule(((%Ct * 1000) + 500), "delete"); for(%i = 1; %i <= %ct; %i++) { %time = %i * 1000; - schedule(%time, 0, "StartAZombie", %SumPos, %type); + schedule(%time, 0, "TWM2Lib_Zombie_Core", "SpawnZombie", "zSpawnCommand", %type, %SumPos); } } diff --git a/scripts/TWM2/Zombie/ZombieTypes/VolatileRavager.cs b/scripts/TWM2/Zombie/ZombieTypes/VolatileRavager.cs new file mode 100644 index 0000000..2b8bd70 --- /dev/null +++ b/scripts/TWM2/Zombie/ZombieTypes/VolatileRavager.cs @@ -0,0 +1,110 @@ +datablock PlayerData(VolatileRavagerZombieArmor) : LightMaleBiodermArmor { + maxDamage = 1.0; + minImpactSpeed = 50; + speedDamageScale = 0.015; + + damageScale[$DamageType::M1700] = 2.0; + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; +}; + +datablock ShapeBaseImageData(ZExplosivePack) { + shapeFile = "pack_upgrade_satchel.dts"; + emap = false; +}; + +function VRavZombiemovetotarget(%zombie){ + if(!isobject(%Zombie)) + return; + if(%Zombie.getState() $= "dead") + return; + %pos = %zombie.getworldboxcenter(); + %closestClient = ZombieLookForTarget(%zombie); + %closestDistance = getWord(%closestClient,1); + %closestClient = getWord(%closestClient,0).Player; + if(%closestDistance <= $zombie::detectDist){ + if(%zombie.hastarget != 1){ + %zombie.hastarget = 1; + } + %zombie.setActionThread("scoutRoot",true); + %upvec = "250"; + if(Game.CheckModifier("Kamakazi") == 1) { + %fmultiplier = $Zombie::FForwardSpeed * 0.5 * 5; + } + else { + %fmultiplier = $Zombie::FForwardSpeed * 0.5; + } + + //ka-booma :) + if(%closestDistance < 9) { + if(%zombie.isAlive()) { + if(Game.CheckModifier("TheDestiny") == 1) { + ServerPlay3D("SatchelChargeExplosionSound", %zombie.getPosition()); + %c4 = new Item() { + datablock = SatchelChargeThrown; + position = %zombie.getPosition(); + scale = ".1 .1 .1"; + }; + MissionCleanup.add(%c4); + schedule(770, 0, "C4GoBoom", %c4); + return; + } + else { + ServerPlay3D("SatchelChargeExplosionSound", %zombie.getPosition()); + %c4 = new Item() { + datablock = C4Deployed; + position = %zombie.getPosition(); + scale = ".1 .1 .1"; + }; + MissionCleanup.add(%c4); + schedule(770, 0, "C4GoBoom", %c4); + return; + } + } + } + + //moanStuff + %chance = (getrandom() * 50); + if(%chance >= 49) { + %chance = (getRandom() * 12); + if(%chance <= 11) + serverPlay3d("ZombieMoan",%zombie.getWorldBoxCenter()); + else + serverPlay3d("ZombieHOWL",%zombie.getWorldBoxCenter()); + } + + %vector = ZgetFacingDirection(%zombie,%closestClient,%pos); + + //Move Stuff + if(%closestDistance <= $zombie::lungDist && %zombie.canjump == 1 && getword(%vector, 2) <= "0.8" ){ + %zombie.setvelocity("0 0 0"); + %fmultiplier = (%fmultiplier * 2); + %upvec = (%upvec * 3.5); + %zombie.canjump = 0; + schedule(2000, %zombie, "Zsetjump", %zombie); + } + %vector = vectorscale(%vector, %Fmultiplier); + %x = Getword(%vector,0); + %y = Getword(%vector,1); + %z = Getword(%vector,2); + if(%z >= "1200" && %zombie.canjump == 1){ + %zombie.setvelocity("0 0 0"); + %upvec = (%upvec * 8); + %x = (%x * 0.5); + %y = (%y * 0.5); + %zombie.canjump = 0; + schedule(2500, %zombie, "Zsetjump", %zombie); + } + + %vector = %x@" "@%y@" "@%upvec; + %zombie.applyImpulse(%pos, %vector); + } + else if(%zombie.hastarget == 1){ + %zombie.hastarget = 0; + %zombie.zombieRmove = schedule(100, %zombie, "ZSetRandomMove", %zombie); + %zombie.setActionThread("ski",true); + } + %zombie.moveloop = schedule(500, %zombie, "VRavZombiemovetotarget", %zombie); +} diff --git a/scripts/admin.cs b/scripts/admin.cs index 039feaf..04a7a48 100644 --- a/scripts/admin.cs +++ b/scripts/admin.cs @@ -13,6 +13,8 @@ $VoteMessage["VoteGreedMode", 0] = "enable Hoard Mode"; $VoteMessage["VoteGreedMode", 1] = "disable Hoard Mode"; $VoteMessage["VoteHoardMode", 0] = "enable Greed Mode"; $VoteMessage["VoteHoardMode", 1] = "disable Greed Mode"; +$VoteMessage["VoteLivingWorldMode", 0] = "enable Living World Mode"; +$VoteMessage["VoteLivingWorldMode", 1] = "disable Living World Mode"; // JTL $VoteMessage["VotePurebuild", 0] = "enable pure building"; $VoteMessage["VotePurebuild", 1] = "disable pure building"; @@ -57,421 +59,343 @@ $VoteMessage["VotePrisonDeploySpam", 0] = "enable jailing deploy spammers"; $VoteMessage["VotePrisonDeploySpam", 1] = "disable jailing deploy spammers"; // End JTL -function serverCmdStartNewVote(%client, %typeName, %arg1, %arg2, %arg3, %arg4, %playerVote) -{ - //DEMO VERSION - only voteKickPlayer is allowed - if ((isDemo()) && %typeName !$= "VoteKickPlayer") - { - messageClient(%client, '', "All voting options except to kick a player are disabled in the DEMO VERSION."); - return; - } - - if(%typeName $= "VoteChangeMission" && !$TWM2::AllowCMVotes && !%client.isSuperAdmin) { - messageClient(%client, '', "The host has disabled mission votes, only Super Admins may change the mission."); - return; - } +function serverCmdStartNewVote(%client, %typeName, %arg1, %arg2, %arg3, %arg4, %playerVote) { + if(%typeName $= "VoteChangeMission" && !$TWM2::AllowCMVotes && !%client.isSuperAdmin) { + messageClient(%client, '', "The host has disabled mission votes, only Super Admins may change the mission."); + return; + } + // haha - who gets the last laugh... No admin for you! + if( %typeName $= "VoteAdminPlayer" && (!$Host::allowAdminPlayerVotes && !%client.isSuperAdmin)) + return; - // haha - who gets the last laugh... No admin for you! - if( %typeName $= "VoteAdminPlayer" && (!$Host::allowAdminPlayerVotes && !%client.isSuperAdmin)) - return; + %typePass = true; - %typePass = true; + // if not a valid vote, turn back. + //Phantom139: Spring Cleaning... TWM2 3.9.2 + // Old format: if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteOnlyOwnerCascade" ) + if($VoteMessage[%typeName $= "") { + switch$(%typeName): + case "VoteTeamDamage" or "VoteHoardMode" or "VoteGreedMode" or "VotePurebuild" or "VoteLivingWorldMode" + or "VoteCascadeMode" or "VoteExpertMode" or "VoteVehicles" or "VoteSatchelCharge" or "VoteOnlyOwnerDeconstruct" + or "VoteOnlyOwnerCascade" or "VoteOnlyOwnerRotate" or "VoteOnlyOwnerCubicReplace" or "VoteRemoveDeployables" + or "VoteGlobalPowerCheck" or "VoteRemoveDupDeployables" or "VoteRemoveNonPoweredDeployables" or "VoteRemoveOrphanedDeployables" + or "VoteInvincibleArmors" or "VoteInvincibleDeployables" or "VoteUndergroundMode" or "VoteHazardMode" or "VotePrison" + or "VotePrisonKilling" or "VotePrisonTeamKilling" or "VotePrisonDeploySpam": + // Looks like we missed a message, but the type is ok, allow pass. + default: + %typePass = false; + } + // End JTL - // if not a valid vote, turn back. - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteTeamDamage" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteHoardMode" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteGreedMode" ) -// JTL - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VotePurebuild" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteCascadeMode" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteExpertMode" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteVehicles" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteSatchelCharge" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteOnlyOwnerDeconstruct" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteOnlyOwnerCascade" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteOnlyOwnerRotate" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteOnlyOwnerCubicReplace" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteRemoveDeployables" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteGlobalPowerCheck" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteRemoveDupDeployables" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteRemoveNonPoweredDeployables" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteRemoveOrphanedDeployables" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteInvincibleArmors" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteInvincibleDeployables" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteUndergroundMode" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VoteHazardMode" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VotePrison" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VotePrisonKilling" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VotePrisonTeamKilling" ) - if( $VoteMessage[ %typeName ] $= "" && %typeName !$= "VotePrisonDeploySpam" ) - %typePass = false; -// End JTL + if(( $VoteMessage[ %typeName, $TeamDamage ] $= "" && %typeName $= "VoteTeamDamage" )) + %typePass = false; + // JTL + if(( $VoteMessage[ %typeName, $Host::Purebuild ] $= "" && %typeName $= "VotePurebuild" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::LivingWorldMode ] $= "" && %typeName $= "VoteLivingWorldMode" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::Cascade ] $= "" && %typeName $= "VoteCascadeMode" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::ExpertMode ] $= "" && %typeName $= "VoteExpertMode" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::Vehicles ] $= "" && %typeName $= "VoteVehicles" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::SatchelChargeEnabled ] $= "" && %typeName $= "VoteSatchelCharge" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::OnlyOwnerDeconstruct ] $= "" && %typeName $= "VoteOnlyOwnerDeconstruct" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::OnlyOwnerCascade ] $= "" && %typeName $= "VoteOnlyOwnerCascade" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::OnlyOwnerRotate ] $= "" && %typeName $= "VoteOnlyOwnerRotate" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::OnlyOwnerCubicReplace ] $= "" && %typeName $= "VoteOnlyOwnerCubicReplace" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::InvincibleArmors ] $= "" && %typeName $= "VoteInvincibleArmors" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::InvincibleDeployables ] $= "" && %typeName $= "VoteInvincibleDeployables" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::AllowUnderground ] $= "" && %typeName $= "VoteUndergroundMode" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::Hazard::Enabled ] $= "" && %typeName $= "VoteHazardMode" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::Prison::Enabled ] $= "" && %typeName $= "VotePrison" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::Prison::Kill ] $= "" && %typeName $= "VotePrisonKilling" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::Prison::TeamKill ] $= "" && %typeName $= "VotePrisonTeamKilling" )) + %typePass = false; + if(( $VoteMessage[ %typeName, $Host::Prison::DeploySpam ] $= "" && %typeName $= "VotePrisonDeploySpam" )) + %typePass = false; + // End JTL - if(( $VoteMessage[ %typeName, $TeamDamage ] $= "" && %typeName $= "VoteTeamDamage" )) - %typePass = false; -// JTL - if(( $VoteMessage[ %typeName, $Host::Purebuild ] $= "" && %typeName $= "VotePurebuild" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::Cascade ] $= "" && %typeName $= "VoteCascadeMode" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::ExpertMode ] $= "" && %typeName $= "VoteExpertMode" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::Vehicles ] $= "" && %typeName $= "VoteVehicles" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::SatchelChargeEnabled ] $= "" && %typeName $= "VoteSatchelCharge" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::OnlyOwnerDeconstruct ] $= "" && %typeName $= "VoteOnlyOwnerDeconstruct" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::OnlyOwnerCascade ] $= "" && %typeName $= "VoteOnlyOwnerCascade" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::OnlyOwnerRotate ] $= "" && %typeName $= "VoteOnlyOwnerRotate" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::OnlyOwnerCubicReplace ] $= "" && %typeName $= "VoteOnlyOwnerCubicReplace" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::InvincibleArmors ] $= "" && %typeName $= "VoteInvincibleArmors" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::InvincibleDeployables ] $= "" && %typeName $= "VoteInvincibleDeployables" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::AllowUnderground ] $= "" && %typeName $= "VoteUndergroundMode" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::Hazard::Enabled ] $= "" && %typeName $= "VoteHazardMode" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::Prison::Enabled ] $= "" && %typeName $= "VotePrison" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::Prison::Kill ] $= "" && %typeName $= "VotePrisonKilling" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::Prison::TeamKill ] $= "" && %typeName $= "VotePrisonTeamKilling" )) - %typePass = false; - if(( $VoteMessage[ %typeName, $Host::Prison::DeploySpam ] $= "" && %typeName $= "VotePrisonDeploySpam" )) - %typePass = false; -// End JTL + if( !%typePass ) + return; // -> bye ;) - if( !%typePass ) - return; // -> bye ;) + // z0dd - ZOD, 10/03/02. This was busted, BanPlayer was never delt with. + if( %typeName $= "BanPlayer" ) { + if( !%client.isSuperAdmin || %arg1.isAdmin ) { + return; // -> bye ;) + } + else { + ban( %arg1, %client ); + return; + } + } - // z0dd - ZOD, 10/03/02. This was busted, BanPlayer was never delt with. - if( %typeName $= "BanPlayer" ) - { - if( !%client.isSuperAdmin || %arg1.isAdmin ) - { - return; // -> bye ;) - } - else - { - ban( %arg1, %client ); - return; - } - } + %isAdmin = ( %client.isAdmin || %client.isSuperAdmin ); - %isAdmin = ( %client.isAdmin || %client.isSuperAdmin ); + // JTL + //Phantom139: Spring Cleaning... TWM2 3.9.2 + if(!%isAdmin) { + switch$(%typeName) { + case "VoteVehicles" or "VoteSatchelCharge" or "VoteOnlyOwnerDeconstruct" or "VoteOnlyOwnerCascade" + or "VoteOnlyOwnerRotate" or "VoteOnlyOwnerCubicReplace" or "VoteRemoveDeployables" or "VoteGlobalPowerCheck" + or "VoteRemoveDupDeployables" or "VoteRemoveNonPoweredDeployables" or "VoteRemoveOrphanedDeployables" + or "VoteInvincibleArmors" or "VoteInvincibleDeployables" or "VoteUndergroundMode" or "VoteHazardMode" + or "VotePrison" or "VotePrisonKilling" or "VotePrisonTeamKilling" or "VotePrisonDeploySpam": + %typePass = false; + } + } -// JTL - if(%typeName $= "VoteVehicles" && !%isAdmin) - if(%typeName $= "VoteVehicles" && !%isAdmin) - if(%typeName $= "VoteSatchelCharge" && !%isAdmin) - if(%typeName $= "VoteOnlyOwnerDeconstruct" && !%isAdmin) - if(%typeName $= "VoteOnlyOwnerCascade" && !%isAdmin) - if(%typeName $= "VoteOnlyOwnerRotate" && !%isAdmin) - if(%typeName $= "VoteOnlyOwnerCubicReplace" && !%isAdmin) - if(%typeName $= "VoteRemoveDeployables" && !%isAdmin) - if(%typeName $= "VoteGlobalPowerCheck" && !%isAdmin) - if(%typeName $= "VoteRemoveDupDeployables" && !%isAdmin) - if(%typeName $= "VoteRemoveNonPoweredDeployables" && !%isAdmin) - if(%typeName $= "VoteRemoveOrphanedDeployables" && !%isAdmin) - if(%typeName $= "VoteInvincibleArmors" && !%isAdmin) - if(%typeName $= "VoteInvincibleDeployables" && !%isAdmin) - if(%typeName $= "VoteUndergroundMode" && !%isAdmin) - if(%typeName $= "VoteHazardMode" && !%isAdmin) - if(%typeName $= "VotePrison" && !%isAdmin) - if(%typeName $= "VotePrisonKilling" && !%isAdmin) - if(%typeName $= "VotePrisonTeamKilling" && !%isAdmin) - if(%typeName $= "VotePrisonDeploySpam" && !%isAdmin) - %typePass = false; + if( !%typePass ) + return; // -> bye ;) + // End JTL - if( !%typePass ) - return; // -> bye ;) -// End JTL + // keep these under the server's control. I win. + if( !%playerVote ) + %actionMsg = $VoteMessage[ %typeName ]; + else if( %typeName $= "VoteTeamDamage" || %typeName $= "VoteGreedMode" || %typeName $= "VoteHoardMode" ) + %actionMsg = $VoteMessage[ %typeName, $TeamDamage ]; + // JTL + else if( %typeName $= "VotePurebuild" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Purebuild ]; + else if( %typeName $= "VoteLivingWorldMode" ) + %actionMsg = $VoteMessage[ %typeName, $Host::LivingWorldMode ]; + else if( %typeName $= "VoteCascadeMode" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Cascade ]; + else if( %typeName $= "VoteExpertMode" ) + %actionMsg = $VoteMessage[ %typeName, $Host::ExpertMode ]; + else if( %typeName $= "VoteVehicles" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Vehicles ]; + else if( %typeName $= "VoteSatchelCharge" ) + %actionMsg = $VoteMessage[ %typeName, $Host::SatchelChargeEnabled ]; + else if( %typeName $= "VoteOnlyOwnerDeconstruct" ) + %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerDeconstruct ]; + else if( %typeName $= "VoteOnlyOwnerCascade" ) + %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerCascade ]; + else if( %typeName $= "VoteOnlyOwnerRotate" ) + %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerRotate ]; + else if( %typeName $= "VoteOnlyOwnerCubicReplace" ) + %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerCubicReplace ]; + else if( %typeName $= "VoteInvincibleArmors" ) + %actionMsg = $VoteMessage[ %typeName, $Host::InvincibleArmors ]; + else if( %typeName $= "VoteInvincibleDeployables" ) + %actionMsg = $VoteMessage[ %typeName, $Host::InvincibleDeployables ]; + else if( %typeName $= "VoteUndergroundMode" ) + %actionMsg = $VoteMessage[ %typeName, $Host::AllowUnderground ]; + else if( %typeName $= "VoteHazardMode" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Hazard::Enabled ]; + else if( %typeName $= "VotePrison" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Prison::Enabled ]; + else if( %typeName $= "VotePrisonKilling" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Prison::Kill ]; + else if( %typeName $= "VotePrisonTeamKilling" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Prison::TeamKill ]; + else if( %typeName $= "VotePrisonDeploySpam" ) + %actionMsg = $VoteMessage[ %typeName, $Host::Prison::DeploySpam ]; + // End JTL + else + %actionMsg = $VoteMessage[ %typeName ]; - // keep these under the server's control. I win. - if( !%playerVote ) - %actionMsg = $VoteMessage[ %typeName ]; - else if( %typeName $= "VoteTeamDamage" || %typeName $= "VoteGreedMode" || %typeName $= "VoteHoardMode" ) - %actionMsg = $VoteMessage[ %typeName, $TeamDamage ]; -// JTL - else if( %typeName $= "VotePurebuild" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Purebuild ]; - else if( %typeName $= "VoteCascadeMode" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Cascade ]; - else if( %typeName $= "VoteExpertMode" ) - %actionMsg = $VoteMessage[ %typeName, $Host::ExpertMode ]; - else if( %typeName $= "VoteVehicles" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Vehicles ]; - else if( %typeName $= "VoteSatchelCharge" ) - %actionMsg = $VoteMessage[ %typeName, $Host::SatchelChargeEnabled ]; - else if( %typeName $= "VoteOnlyOwnerDeconstruct" ) - %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerDeconstruct ]; - else if( %typeName $= "VoteOnlyOwnerCascade" ) - %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerCascade ]; - else if( %typeName $= "VoteOnlyOwnerRotate" ) - %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerRotate ]; - else if( %typeName $= "VoteOnlyOwnerCubicReplace" ) - %actionMsg = $VoteMessage[ %typeName, $Host::OnlyOwnerCubicReplace ]; - else if( %typeName $= "VoteInvincibleArmors" ) - %actionMsg = $VoteMessage[ %typeName, $Host::InvincibleArmors ]; - else if( %typeName $= "VoteInvincibleDeployables" ) - %actionMsg = $VoteMessage[ %typeName, $Host::InvincibleDeployables ]; - else if( %typeName $= "VoteUndergroundMode" ) - %actionMsg = $VoteMessage[ %typeName, $Host::AllowUnderground ]; - else if( %typeName $= "VoteHazardMode" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Hazard::Enabled ]; - else if( %typeName $= "VotePrison" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Prison::Enabled ]; - else if( %typeName $= "VotePrisonKilling" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Prison::Kill ]; - else if( %typeName $= "VotePrisonTeamKilling" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Prison::TeamKill ]; - else if( %typeName $= "VotePrisonDeploySpam" ) - %actionMsg = $VoteMessage[ %typeName, $Host::Prison::DeploySpam ]; -// End JTL - else - %actionMsg = $VoteMessage[ %typeName ]; + if( !%client.canVote && !%isAdmin ) + return; - if( !%client.canVote && !%isAdmin ) - return; + if ( ( !%isAdmin || ( %arg1.isAdmin && ( %client != %arg1 ) ) ) && // z0dd - ToS 4/2/02: Allow SuperAdmins to kick Admins + !( ( %typeName $= "VoteKickPlayer" ) && %client.isSuperAdmin ) ) { // z0dd - ToS 4/2/02: Allow SuperAdmins to kick Admins + %teamSpecific = false; + %gender = (%client.sex $= "Male" ? 'he' : 'she'); + if ( Game.scheduleVote $= "" ) { + %clientsVoting = 0; + //send a message to everyone about the vote... + if ( %playerVote ) { + %teamSpecific = ( %typeName $= "VoteKickPlayer" ) && ( Game.numTeams > 1 ); + %kickerIsObs = %client.team == 0; + %kickeeIsObs = %arg1.team == 0; + %sameTeam = %client.team == %arg1.team; - if ( ( !%isAdmin || ( %arg1.isAdmin && ( %client != %arg1 ) ) ) && // z0dd - ToS 4/2/02: Allow SuperAdmins to kick Admins - !( ( %typeName $= "VoteKickPlayer" ) && %client.isSuperAdmin ) ) // z0dd - ToS 4/2/02: Allow SuperAdmins to kick Admins - { - %teamSpecific = false; - %gender = (%client.sex $= "Male" ? 'he' : 'she'); - if ( Game.scheduleVote $= "" ) - { - %clientsVoting = 0; + if( %kickeeIsObs ) { + %teamSpecific = false; + %sameTeam = false; + } - //send a message to everyone about the vote... - if ( %playerVote ) - { - %teamSpecific = ( %typeName $= "VoteKickPlayer" ) && ( Game.numTeams > 1 ); - %kickerIsObs = %client.team == 0; - %kickeeIsObs = %arg1.team == 0; - %sameTeam = %client.team == %arg1.team; + if(( !%sameTeam && %teamSpecific) && %typeName !$= "VoteAdminPlayer") { + messageClient(%client, '', "\c2Player votes must be team based."); + return; + } - if( %kickeeIsObs ) - { - %teamSpecific = false; - %sameTeam = false; - } + // kicking is team specific + if( %typeName $= "VoteKickPlayer" ) { + if(%arg1.isSuperAdmin) { + messageClient(%client, '', '\c2You can not %1 %2, %3 is a Super Admin!', %actionMsg, %arg1.name, %gender); + return; + } - if(( !%sameTeam && %teamSpecific) && %typeName !$= "VoteAdminPlayer") - { - messageClient(%client, '', "\c2Player votes must be team based."); - return; - } + Game.kickClient = %arg1; + Game.kickClientName = %arg1.name; + Game.kickGuid = %arg1.guid; + Game.kickTeam = %arg1.team; - // kicking is team specific - if( %typeName $= "VoteKickPlayer" ) - { - if(%arg1.isSuperAdmin) - { - messageClient(%client, '', '\c2You can not %1 %2, %3 is a Super Admin!', %actionMsg, %arg1.name, %gender); - return; - } + if(%teamSpecific) { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); - Game.kickClient = %arg1; - Game.kickClientName = %arg1.name; - Game.kickGuid = %arg1.guid; - Game.kickTeam = %arg1.team; + if (%cl.team == %client.team && !%cl.isAIControlled()) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name); + %clientsVoting++; + } + } + } + else { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); + if ( !%cl.isAIControlled() ) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name); + %clientsVoting++; + } + } + } + } + else { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); + if ( !%cl.isAIControlled() ) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name); + %clientsVoting++; + } + } + } + } + else if ( %typeName $= "VoteChangeMission" ) { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); + if ( !%cl.isAIControlled() ) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3 (%4).', %client.name, %actionMsg, %arg1, %arg2 ); + %clientsVoting++; + } + } + } + else if (%arg1 !$= 0) { + if (%arg2 !$= 0) { + if(%typeName $= "VoteTournamentMode") { + %admin = getAdmin(); + if(%admin > 0) { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); + if ( !%cl.isAIControlled() ) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 Tournament Mode (%3).', %client.name, %actionMsg, %arg1); + %clientsVoting++; + } + } + } + else { + messageClient( %client, 'clientMsg', 'There must be a server admin to play in Tournament Mode.'); + return; + } + } + else { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); + if ( !%cl.isAIControlled() ) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3 %4.', %client.name, %actionMsg, %arg1, %arg2); + %clientsVoting++; + } + } + } + } + else { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); + if ( !%cl.isAIControlled() ) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1); + %clientsVoting++; + } + } + } + } + else { + for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) { + %cl = ClientGroup.getObject( %idx ); + if ( !%cl.isAIControlled() ) { + messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2.', %client.name, %actionMsg); + %clientsVoting++; + } + } + } + // open the vote hud for all clients that will participate in this vote + if(%teamSpecific) { + for ( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ ) { + %cl = ClientGroup.getObject( %clientIndex ); - if(%teamSpecific) - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); + if(%cl.team == %client.team && !%cl.isAIControlled()) + messageClient(%cl, 'openVoteHud', "", %clientsVoting, ($Host::VotePassPercent / 100)); + } + } + else { + for ( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ ) { + %cl = ClientGroup.getObject( %clientIndex ); + if ( !%cl.isAIControlled() ) + messageClient(%cl, 'openVoteHud', "", %clientsVoting, ($Host::VotePassPercent / 100)); + } + } - if (%cl.team == %client.team && !%cl.isAIControlled()) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name); - %clientsVoting++; - } - } - } - else - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); - if ( !%cl.isAIControlled() ) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name); - %clientsVoting++; - } - } - } - } - else - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); - if ( !%cl.isAIControlled() ) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name); - %clientsVoting++; - } - } - } - } - else if ( %typeName $= "VoteChangeMission" ) - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); - if ( !%cl.isAIControlled() ) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3 (%4).', %client.name, %actionMsg, %arg1, %arg2 ); - %clientsVoting++; - } - } - } - else if (%arg1 !$= 0) - { - if (%arg2 !$= 0) - { - if(%typeName $= "VoteTournamentMode") - { - %admin = getAdmin(); - if(%admin > 0) - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); - if ( !%cl.isAIControlled() ) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 Tournament Mode (%3).', %client.name, %actionMsg, %arg1); - %clientsVoting++; - } - } - } - else - { - messageClient( %client, 'clientMsg', 'There must be a server admin to play in Tournament Mode.'); - return; - } - } - else - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); - if ( !%cl.isAIControlled() ) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3 %4.', %client.name, %actionMsg, %arg1, %arg2); - %clientsVoting++; - } - } - } - } - else - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); - if ( !%cl.isAIControlled() ) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1); - %clientsVoting++; - } - } - } - } - else - { - for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ ) - { - %cl = ClientGroup.getObject( %idx ); - if ( !%cl.isAIControlled() ) - { - messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2.', %client.name, %actionMsg); - %clientsVoting++; - } - } - } + clearVotes(); + //SIG + Game.voteType = %typeName; + Game.VClient = %client; + Game.Varg1 = %arg1; + Game.Varg2 = %arg2; + Game.Varg3 = %arg3; + Game.Varg4 = %arg4; + //kthx + Game.scheduleVote = schedule( ($Host::VoteTime * 1000), 0, "calcVotes", %typeName, %arg1, %arg2, %arg3, %arg4 ); + %client.vote = true; + messageAll('addYesVote', ""); - // open the vote hud for all clients that will participate in this vote - if(%teamSpecific) - { - for ( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ ) - { - %cl = ClientGroup.getObject( %clientIndex ); + if(!%client.team == 0) + clearBottomPrint(%client); + } + else + messageClient( %client, 'voteAlreadyRunning', '\c2A vote is already in progress.' ); + } + else { + if ( Game.scheduleVote !$= "" && Game.voteType $= %typeName ) { + messageAll('closeVoteHud', ""); + cancel(Game.scheduleVote); + Game.scheduleVote = ""; + } - if(%cl.team == %client.team && !%cl.isAIControlled()) - messageClient(%cl, 'openVoteHud', "", %clientsVoting, ($Host::VotePassPercent / 100)); - } - } - else - { - for ( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ ) - { - %cl = ClientGroup.getObject( %clientIndex ); - if ( !%cl.isAIControlled() ) - messageClient(%cl, 'openVoteHud', "", %clientsVoting, ($Host::VotePassPercent / 100)); - } - } + // if this is a superAdmin, don't kick or ban + if(%arg1 != %client) { + if(!%arg1.isSuperAdmin) { + // Set up kick/ban values: + if ( %typeName $= "VoteBanPlayer" || %typeName $= "VoteKickPlayer" ) { + Game.kickClient = %arg1; + Game.kickClientName = %arg1.name; + Game.kickGuid = %arg1.guid; + Game.kickTeam = %arg1.team; + } - clearVotes(); - //SIG - Game.voteType = %typeName; - Game.VClient = %client; - Game.Varg1 = %arg1; - Game.Varg2 = %arg2; - Game.Varg3 = %arg3; - Game.Varg4 = %arg4; - //kthx - Game.scheduleVote = schedule( ($Host::VoteTime * 1000), 0, "calcVotes", %typeName, %arg1, %arg2, %arg3, %arg4 ); - %client.vote = true; - messageAll('addYesVote', ""); - - if(!%client.team == 0) - clearBottomPrint(%client); - } - else - messageClient( %client, 'voteAlreadyRunning', '\c2A vote is already in progress.' ); - } - else - { - if ( Game.scheduleVote !$= "" && Game.voteType $= %typeName ) - { - messageAll('closeVoteHud', ""); - cancel(Game.scheduleVote); - Game.scheduleVote = ""; - } - - // if this is a superAdmin, don't kick or ban - if(%arg1 != %client) - { - if(!%arg1.isSuperAdmin) - { - // Set up kick/ban values: - if ( %typeName $= "VoteBanPlayer" || %typeName $= "VoteKickPlayer" ) - { - Game.kickClient = %arg1; - Game.kickClientName = %arg1.name; - Game.kickGuid = %arg1.guid; - Game.kickTeam = %arg1.team; - } - - //Tinman - PURE servers can't call "eval" - //Mark - True, but neither SHOULD a normal server - // - thanks Ian Hardingham - Game.evalVote(%typeName, %client, %arg1, %arg2, %arg3, %arg4); - } - else - messageClient(%client, '', '\c2You can not %1 %2, %3 is a Super Admin!', %actionMsg, %arg1.name, %gender); - } - } - - %client.canVote = false; - %client.rescheduleVote = schedule( ($Host::voteSpread * 1000) + ($Host::voteTime * 1000) , 0, "resetVotePrivs", %client ); + //Tinman - PURE servers can't call "eval" + //Mark - True, but neither SHOULD a normal server + // - thanks Ian Hardingham + Game.evalVote(%typeName, %client, %arg1, %arg2, %arg3, %arg4); + } + else + messageClient(%client, '', '\c2You can not %1 %2, %3 is a Super Admin!', %actionMsg, %arg1.name, %gender); + } + } + %client.canVote = false; + %client.rescheduleVote = schedule( ($Host::voteSpread * 1000) + ($Host::voteTime * 1000) , 0, "resetVotePrivs", %client ); } function resetVotePrivs( %client ) diff --git a/scripts/defaultGame.cs b/scripts/defaultGame.cs index 1a1afe2..1edc19b 100644 --- a/scripts/defaultGame.cs +++ b/scripts/defaultGame.cs @@ -2856,6 +2856,27 @@ function DefaultGame::sendGameVoteMenu( %game, %client, %key ) messageClient( %client, 'MsgVoteItem', "", %key, 'VotePurebuild', 'disable pure building', '[\c1pure\c0] Vote to Disable Pure Building' ); else messageClient( %client, 'MsgVoteItem', "", %key, 'VotePurebuild', 'enable pure building', '[\c1pure\c0] Vote to Enable Pure Building' ); + + //Phantom139: TWM2 3.9.2: Living World + if($CurrentMissionType $= "Construction") { + if($Host::Purebuild == 0) { + if($Host::LivingWorldMode == 1) { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'disable living world mode', '[\c1pure\c0] Vote to Disable Living World Mode' ); + } + else { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'enable living world mode', '[\c1pure\c0] Vote to Enable Living World Mode' ); + } + } + else { + if($Host::LivingWorldMode == 1) { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'disable living world mode', '[\c1pure\c0] Vote to Disable Living World Mode' ); + } + else { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'enable living world mode', '[\c1pure\c0] Vote to Enable Living World Mode (Will Disable Purebuild)' ); + } + } + } + if ( $Host::ExpertMode == 1) messageClient( %client, 'MsgVoteItem', "", %key, 'VoteExpertMode', 'disable expert mode', '[\c1pure\c0] Vote to Disable Expert Mode' ); else @@ -2887,10 +2908,27 @@ function DefaultGame::sendGameVoteMenu( %game, %client, %key ) else messageClient( %client, 'MsgVoteItem', "", %key, 'VoteTeamDamage', 'enable team damage', 'Enable Team Damage' ); - if ( $Host::Purebuild == 1 ) + if ( $Host::Purebuild == 1 ) { messageClient( %client, 'MsgVoteItem', "", %key, 'VotePurebuild', 'disable pure building', '[\c1pure\c0] Disable Pure Building' ); + if($CurrentMissionType $= "Construction") { + if($Host::LivingWorldMode == 1) { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'disable living world mode', '[\c1LWM\c0] Disable Living World Mode' ); + } + else { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'enable living world mode', '[\c1LWM\c0] Enable Living World Mode (Will Disable Purebuild)' ); + } + } + } else messageClient( %client, 'MsgVoteItem', "", %key, 'VotePurebuild', 'enable pure building', '[\c1pure\c0] Enable Pure Building' ); + if($CurrentMissionType $= "Construction") { + if($Host::LivingWorldMode == 1) { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'disable living world mode', '[\c1LWM\c0] Disable Living World Mode' ); + } + else { + messageClient( %client, 'MsgVoteItem', "", %key, 'VoteLivingWorldMode', 'enable living world mode', '[\c1LWM\c0] Enable Living World Mode' ); + } + } } } @@ -3018,6 +3056,7 @@ function DefaultGame::evalVote(%game, %typeName, %admin, %arg1, %arg2, %arg3, %a case "voteGreedMode": %game.voteGreedMode(%admin, %arg1, %arg2, %arg3, %arg4); case "voteHoardMode": %game.voteHoardMode(%admin, %arg1, %arg2, %arg3, %arg4); case "votePurebuild": %game.votePurebuild(%admin, %arg1, %arg2, %arg3, %arg4); + case "VoteLivingWorldMode": %game.voteLivingWorldMode(%admin, %arg1, %arg2, %arg3, %arg4); case "voteCascadeMode": %game.voteCascadeMode(%admin, %arg1, %arg2, %arg3, %arg4); case "voteExpertMode": %game.voteExpertMode(%admin, %arg1, %arg2, %arg3, %arg4); case "VoteVehicles": %game.VoteVehicles(%admin, %arg1, %arg2, %arg3, %arg4); @@ -3043,8 +3082,11 @@ function DefaultGame::evalVote(%game, %typeName, %admin, %arg1, %arg2, %arg3, %a } } -function DefaultGame::voteStartBoss(%game, %admin, %boss, %abbrev) -{ +function DefaultGame::voteStartBoss(%game, %admin, %boss, %abbrev) { + if($Host::LivingWorldMode == 1) { + messageAll('MsgVoteFailed', "\c2Boss spawn vote not allowed in Living World Mode, Vote Failed..."); + return; + } if(%admin) { messageAll('MsgAdminForce', "\c2"@%admin.namebase@" has forcibly spawned "@%boss@" (TWM 2 Boss)."); @@ -3240,6 +3282,57 @@ function DefaultGame::votePurebuild(%game, %admin) logEcho("purebuild "@%setto SPC %cause); } +//------------------------------------------------------------------------------ +function DefaultGame::voteLivingWorldMode(%game, %admin) { + %setto = ""; + %cause = ""; + if(%admin) { + if($Host::LivingWorldMode == 1) { + messageAll('MsgAdminForce', "\c2"@%admin.namebase@" has disabled living world mode."); + livingWorldOff(); + %setto = "disabled"; + } + else { + messageAll('MsgAdminForce', "\c2"@%admin.namebase@" has enabled living world mode."); + livingWorldOn(); + %setto = "enabled"; + if($Host::Purebuild == 1) { + messageAll('MsgAdminForce', "\c2Purebuild has been forced off due to living world mode being enabled."); + purebuildOff(); + } + } + %cause = "(admin)"; + } + else { + %totalVotes = %game.totalVotesFor + %game.totalVotesAgainst; + if(%totalVotes > 0 && (%game.totalVotesFor / (ClientGroup.getCount() - $HostGameBotCount)) > ($Host::VotePasspercent / 100)) { + if($Host::Purebuild == 1) { + messageAll('MsgVotePassed', '\c2Living world mode was disabled by vote.'); + livingWorldOff(); + %setto = "disabled"; + } + else { + messageAll('MsgVotePassed', '\c2Living world mode was enabled by vote.'); + livingWorldOn(); + %setto = "enabled"; + if($Host::Purebuild == 1) { + messageAll('MsgAdminForce', "\c2Purebuild has been forced off due to living world mode being enabled."); + purebuildOff(); + } + } + %cause = "(vote)"; + } + else { + if($Host::Purebuild == 1) + messageAll('MsgVoteFailed', '\c2Disable living world mode vote did not pass: %1 percent.', mFloor(%game.totalVotesFor/(ClientGroup.getCount() - $HostGameBotCount) * 100)); + else + messageAll('MsgVoteFailed', '\c2Enable living world mode vote did not pass: %1 percent.', mFloor(%game.totalVotesFor/(ClientGroup.getCount() - $HostGameBotCount) * 100)); + } + } + if(%setto !$= "") + logEcho("livingworldmode "@%setto SPC %cause); +} + //------------------------------------------------------------------------------ function DefaultGame::voteCascadeMode(%game, %admin) { diff --git a/scripts/item.cs b/scripts/item.cs index 2f69571..9d4212c 100644 --- a/scripts/item.cs +++ b/scripts/item.cs @@ -233,79 +233,43 @@ function RepairKit::onUse(%data,%obj) { %obj.decInventory(%data,1); %obj.applyRepair(0.2); messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Health Patch Taken.'); - } + } else if (%obj.getDamageLevel() == 0 && %obj.infected && !%obj.onfire) { %obj.decInventory(%data,1); - %obj.infected = 0; - if(isEventPending(%obj.infectedDamage)) - { - cancel(%obj.infectedDamage); - %obj.infectedDamage = ""; - %obj.beats = 0; - %obj.canZkill = 0; - %obj.setcancelimpulse = 1; - schedule(1000,0, "resetattackImpulse" ,%obj); //goodie - } + TWM2Lib_Zombie_Core("cureInfection", %obj); messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Infection Cure Taken.'); - } + } else if (%obj.getDamageLevel() == 0 && !%obj.infected && %obj.onfire) { %obj.decInventory(%data,1); - %obj.onfire = 0; + %obj.onfire = 0; messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Burn Patch Taken.'); - } + } else if (%obj.getDamageLevel() != 0 && %obj.infected && !%obj.onfire) { %obj.decInventory(%data,1); %obj.applyRepair(0.2); - %obj.infected = 0; - if(isEventPending(%obj.infectedDamage)) - { - cancel(%obj.infectedDamage); - %obj.infectedDamage = ""; - %obj.beats = 0; - %obj.canZkill = 0; - %obj.setcancelimpulse = 1; - schedule(1000,0, "resetattackImpulse" ,%obj); //goodie - } + TWM2Lib_Zombie_Core("cureInfection", %obj); messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Health Patch And Infection Cure Taken.'); - } + } else if (%obj.getDamageLevel() != 0 && !%obj.infected && %obj.onfire) { %obj.decInventory(%data,1); %obj.applyRepair(0.2); - %obj.onfire = 0; + %obj.onfire = 0; messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Health Patch And Burn Patch Taken.'); - } + } else if (%obj.getDamageLevel() == 0 && %obj.infected && %obj.onfire) { %obj.decInventory(%data,1); %obj.onfire = 0; - %obj.infected = 0; - if(isEventPending(%obj.infectedDamage)) - { - cancel(%obj.infectedDamage); - %obj.infectedDamage = ""; - %obj.beats = 0; - %obj.canZkill = 0; - %obj.setcancelimpulse = 1; - schedule(1000,0, "resetattackImpulse" ,%obj); //goodie - } + TWM2Lib_Zombie_Core("cureInfection", %obj); messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Burn Patch And Infection Cure Taken.'); - } + } else if (%obj.getDamageLevel() != 0 && %obj.infected && %obj.onfire) { %obj.decInventory(%data,1); - %obj.onfire = 0; + %obj.onfire = 0; %obj.applyRepair(0.2); - %obj.infected = 0; - if(isEventPending(%obj.infectedDamage)) - { - cancel(%obj.infectedDamage); - %obj.infectedDamage = ""; - %obj.beats = 0; - %obj.canZkill = 0; - %obj.setcancelimpulse = 1; - schedule(1000,0, "resetattackImpulse" ,%obj); //goodie - } + TWM2Lib_Zombie_Core("cureInfection", %obj); messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Health Patch, Burn Patch, And Infection Cure Taken.'); - } } +} //---------------------------------------------------------------------------- diff --git a/scripts/packs/Medpack.cs b/scripts/packs/Medpack.cs index 633ab51..1ae5794 100644 --- a/scripts/packs/Medpack.cs +++ b/scripts/packs/Medpack.cs @@ -207,7 +207,7 @@ function MedPackGunImage::onRepair(%this,%obj,%slot){ } if (%targetObject.infected && %targetObject.getState() !$= "dead") { - CureInfection(%targetObject); + TWM2Lib_Zombie_Core("cureInfection", %targetObject); %targetObject.playAudio(0, ShockLanceHitSound); messageclient(%obj.client, 'MsgClient', "\c2Applying Zombie Cure To "@%targetObject.client.namebase@"."); messageclient(%targetObject.client, 'MsgClient', "\c2Zombie Cure Applied By "@%obj.client.namebase@"."); diff --git a/scripts/packs/ZSpawnpack.cs b/scripts/packs/ZSpawnpack.cs index 6ac77ed..c11fe98 100644 --- a/scripts/packs/ZSpawnpack.cs +++ b/scripts/packs/ZSpawnpack.cs @@ -3,15 +3,6 @@ $TeamDeployableMax[ZSpawnDeployable] = 9999; // Zombie Spawn Point //--------------------------------------------------------- -$zombie::detectDist = 100; -$zombie::lungDist = 10; -$zombie::LKillDist = 5; -$zombie::Rupvec = 750; -$zombie::killpoints = 5; - -$Zombie::RAAMThread = "cel1"; -$Zombie::RogThread = "cel1"; - datablock AudioProfile(ZombieMoan) { filename = "fx/environment/growl3.wav"; @@ -442,3 +433,20 @@ function DeployedZSpawnBase::onLosePowerDisabled(%data,%obj) { Cancel(%obj.ZCLoop); Parent::onLosePowerDisabled(%data,%obj); } + +function ZcreateLoop(%obj) { + if(isObject(%obj)) { + if(%obj.timedout == 0){ + if(%obj.numZ <= 2 || %obj.numZ $= "") { + TWM2Lib_Zombie_Core("SpawnZombie", "zPack", %obj); + if(%obj.numZ $= "") { + %obj.numZ = 0; + } + %obj.numZ++; + %obj.timedout = 1; + schedule(10000, 0, "eval", ""@%obj@".timedout = 0;"); + } + } + %obj.ZCLoop = schedule(2000, 0, "ZcreateLoop", %obj); + } +} diff --git a/scripts/player.cs b/scripts/player.cs index be314ab..1ae229d 100644 --- a/scripts/player.cs +++ b/scripts/player.cs @@ -2441,7 +2441,7 @@ function Armor::onNewDataBlock(%this,%obj) function Armor::onDisabled(%this,%obj,%state) { %obj.revived = 0; if(%obj.Infected == 1 && !%obj.iszombie){ - %obj.createTheZ = schedule(14000, %obj, "CreateZombie", %obj); + %obj.createTheZ = schedule(14000, %obj, "TWM2Lib_Zombie_Core", "spawnZombie", "infectedplayer", %obj); %obj.revcheck = schedule(($CorpseTimeoutValue) - %fadeTime, %obj, "checkIfRevived", %obj); } else { @@ -2982,10 +2982,10 @@ function Armor::onCollision(%this,%obj,%col,%forceVehicleNode) %Vector = vectorscale(%col.getvelocity(), 100); %obj.applyimpulse(%obj.getposition(), %Vector); %obj.Infected = 1; - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); %obj.damage(0, %obj.position, 0.2, $DamageType::Zombie); } - else if(%colarmortype $= "FZombieArmor" && %obj.Infected != 1 && %objiszomb != 1 && !%obj.rapierShield){ + else if(%colarmortype $= "RavagerZombieArmor" && %obj.Infected != 1 && %objiszomb != 1 && !%obj.rapierShield){ if(%obj.hit $= ""){ %obj.hit = 1; %obj.setWhiteOut("0.5"); @@ -2993,7 +2993,7 @@ function Armor::onCollision(%this,%obj,%col,%forceVehicleNode) } else if(%obj.hit == 1){ %obj.Infected = 1; - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); } %Vector = vectorscale(%col.getvelocity(), 100); %obj.applyimpulse(%obj.getposition(), %Vector); @@ -3003,7 +3003,7 @@ function Armor::onCollision(%this,%obj,%col,%forceVehicleNode) %Vector = vectorscale(%col.getvelocity(), 100); %obj.applyimpulse(%obj.getposition(), %Vector); %obj.Infected = 1; - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); %obj.damage(0, %obj.position, 0.4, $DamageType::Zombie); } else if(%colarmortype $= "RapierZombieArmor" && %obj.grabbed != 1 && %objiszomb != 1 && !%obj.rapierShield){ @@ -3011,7 +3011,7 @@ function Armor::onCollision(%this,%obj,%col,%forceVehicleNode) if(%chance == 3 && %obj.Infected != 1){ %obj.damage(0, %obj.position, 0.4, $DamageType::Zombie); %obj.Infected = 1; - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); } else { %col.iscarrying = 1; @@ -3024,21 +3024,21 @@ function Armor::onCollision(%this,%obj,%col,%forceVehicleNode) %Vector = vectorscale(%col.getvelocity(), 100); %obj.applyimpulse(%obj.getposition(), %Vector); %obj.Infected = 1; - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); %obj.damage(0, %obj.position, 0.3, $DamageType::Zombie); } else if(%colarmortype $= "SummonerZombieArmor" && %obj.Infected != 1 && %objiszomb != 1 && !%obj.rapierShield){ %Vector = vectorscale(%col.getvelocity(), 100); %obj.applyimpulse(%obj.getposition(), %Vector); %obj.Infected = 1; - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); %obj.damage(0, %obj.position, 0.3, $DamageType::Zombie); } else if(%colarmortype $= "DemonUltraZombieArmor" && %obj.Infected != 1 && %objiszomb != 1 && !%obj.rapierShield){ %Vector = vectorscale(%col.getvelocity(), 100); %obj.applyimpulse(%obj.getposition(), %Vector); %obj.Infected = 1; - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); %obj.damage(0, %obj.position, 0.5, $DamageType::Zombie); } else if((%colarmortype $= "LordRogZombieArmor" && %objiszomb != 1 && !%obj.rapierShield)) { @@ -3098,7 +3098,7 @@ function Armor::onCollision(%this,%obj,%col,%forceVehicleNode) if(%obj.Infected != 1) { %obj.Infected = 1; %obj.damage(0, %obj.position, 0.8, $DamageType::Zombie); - %obj.InfectedLoop = schedule(10, %obj, "InfectLoop", %obj); + %obj.InfectedLoop = schedule(10, %obj, "TWM2Lib_Zombie_Core", "InfectLoop", %obj); } else { %obj.damage(0, %obj.position, 1.2, $DamageType::Zombie); @@ -3407,7 +3407,7 @@ function Armor::damageObject(%data, %targetObject, %sourceObject, %position, %am // they exist as objects, go figure. if(%targetObject.rapiershield && (%damageType != $DamageType::Suicide)) { if(%targetObject.Infected) { - CureInfection(%targetObject); + TWM2Lib_Zombie_Core("cureInfection", %targetObject); } return; } @@ -3428,7 +3428,7 @@ function Armor::damageObject(%data, %targetObject, %sourceObject, %position, %am %armortype = %targetobject.getdatablock().getname(); if (%damageType == $DamageType::ZAcid && %armortype !$= "ZombieArmor" && %armortype !$= "FZombieArmor" && %armortype !$= "LordZombieArmor" && %armortype !$= "DemonZombieArmor" && %armortype !$= "DemonMotherZombieArmor" && %armortype !$= "RapierZombieArmor" && %targetobject.infected != 1 && (%sourceObject.isZombie == 1 || %sourceObject.isBoss == 1)){ %targetObject.Infected = 1; - %targetObject.InfectedLoop = schedule(10, %targetObject, "InfectLoop", %targetObject); + %targetObject.InfectedLoop = schedule(10, %targetObject, "TWM2Lib_Zombie_Core", "InfectLoop", %targetObject); } if (%damageType == $DamageType::RapierShield) { CreateBlood(%targetObject); diff --git a/scripts/vehicles/vehicle_havoc.cs b/scripts/vehicles/vehicle_havoc.cs index ad52ca4..870b070 100644 --- a/scripts/vehicles/vehicle_havoc.cs +++ b/scripts/vehicles/vehicle_havoc.cs @@ -489,10 +489,10 @@ function spawnHunterDropship(%position, %dropPosition, %dropType) { }; MissionCleanup.add(%drop); //attach waypoint, spawn pilot/passengers - %wraith = StartAZombie(vectorAdd(%position, "0 0 100"), 15); + %wraith = TWM2Lib_Zombie_Core("spawnZombie", "zspawncommand", 15, vectorAdd(%position, "0 0 100")); %drop.mountObject(%wraith, 0); for(%i = 0; %i < getWordCount(%dropType); %i++) { - %z = StartAZombie(vectorAdd(%position, "0 0 100"), getWord(%dropType, %i)); + %z = TWM2Lib_Zombie_Core("spawnZombie", "zspawncommand", getWord(%dropType, %i), vectorAdd(%position, "0 0 100")); if(isObject(%z)) { %drop.mountObject(%z, %i+2); //%z.mountObject(%drop, %i+2);