Shifter Zombies, Other Misc Changes

Upgraded the shifter zombie type to the new AI script style, added in
additional flags to zombieCore.cs and moved the zombie moan functioning
to the zombieCore file for easier modification across all types.
This commit is contained in:
Robert Fritzen 2017-12-20 11:39:43 -06:00
parent f7095e8823
commit f4c2eeabc6
8 changed files with 153 additions and 120 deletions

View file

@ -94,6 +94,11 @@ PLEASE NOTE: I've moved all old changelogs into the version_history folder. This
* Replaced the standard lunge with a fire lunge which creates a firey explosion on impact
* Reduced the hit damage of the demon lord from 0.8 to 0.5
* Demon Lords, like the regular demons will no longer infect on collision, but set the player on fire instead
* Shifter
* The change to the shifter teleportation in 3.91 made these zombies ridiculously overpowered, they will be tuned down
* Increased the maximum targeting range of the teleport attack from 200m to 400m
* Increased the cooldown of the teleport attack from 7 seconds to 12.5 seconds
* Shifter zombies will now have to "lock down" for a 1.5 seconds before teleporting, during this time they will be easily targetable
* 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

View file

@ -22,6 +22,24 @@ datablock AudioProfile(ZombieHOWL) {
preload = true;
};
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;
};
//**********************************************
// PARTICLE DATABLOCKS
//**********************************************

View file

@ -85,8 +85,21 @@ $Zombie::DemonZombieFireBombMaxRange = 250;
//$Zombie::RapierUpwardScaling: How fast a rapier zombie will ascend when holding a player
$Zombie::RapierUpwardScaling = 750;
//$Zombie::DemonLord_FireLunge_Thrust: The velocity scalar of the thrust associated with the fire lunge attack
$Zombie::DemonLord_FireLunge_Thrust = 4000;
//$Zombie::DemonLord_FireLunge_MinimumRange: The minimum range following the burst of speed to trigger the fire explosion
$Zombie::DemonLord_FireLunge_MinimumRange = 10;
//$Zombie::DemonLord_FirestormTrigger: How long in miliseconds between the firestorm charge up and the attack itself
$Zombie::DemonLord_FirestormTrigger = 1000;
//$Zombie::DemonLord_MinionSpawnChance: The chance scalar associated with the minion summon attack (The larger this number, the less likely)
$Zombie::DemonLord_MinionSpawnChance = 120;
//$Zombie::Shifter_Teleport_MaximumRange: The maximum range at which a shifter is allowed to teleport from
$Zombie::Shifter_Teleport_MaximumRange = 400;
//$Zombie::Shifter_Teleport_PrepTime: The amount of time (in ms) that it takes for the shifter to lock down before teleporting
$Zombie::Shifter_Teleport_PrepTime = 1500;
//$Zombie::Shifter_Teleport_Cooldown: The cooldown between each teleport
$Zombie::Shifter_Teleport_Cooldown = 12500;
//MISC Globals, Do not edit.
$Zombie::killpoints = 5;
@ -124,9 +137,31 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
%final = %speed * %multiplier;
return %final;
//playzaudio(%zombie, %chanceToPlay, %chanceHowl): Plays the moaning sounds associated with zombies
case "playzaudio":
if(!isObject(%arg1) || %arg1.getState() $= "dead") {
return;
}
if(!isSet(%arg2)) {
%arg2 = 50;
}
if(!isSet(%arg3)) {
%arg3 = 35;
}
%chance = (getrandom() * %arg2);
if(%chance >= (%arg2 - 1)) {
%chance = (getRandom() * %arg3);
if(%chance <= (%arg3 - 1)) {
serverPlay3d("ZombieMoan", %arg1.getWorldBoxCenter());
}
else {
serverPlay3d("ZombieHOWL", %arg1.getWorldBoxCenter());
}
}
//zsetrandommove(%zombie): Activated when the zombie needs to begin random movement
case "zsetrandommove":
if(!isObject(%arg1)) {
if(!isObject(%arg1) || arg1.getState() $= "dead") {
return;
}
%rx = getRandom(-10, 10);
@ -649,27 +684,4 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
%zombie.getDatablock().AI(%zombie);
return %zombie;
}
}
//-----------------------------------------------------------
//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;
};
}

View file

@ -161,9 +161,8 @@ function DemonMotherZombieArmor::AIRoutine(%datablock, %zombie) {
}
}
else if(%dist > 100) {
%rand = getrandom(1,120);
//please, dont ask why i choose this number, it just popped in my head
if(%rand == 94) {
%rand = getRandom(1, $Zombie::DemonLord_MinionSpawnChance);
if(%rand == (($Zombie::DemonLord_MinionSpawnChance / 2) + 1)) {
%datablock.AttackFunction(%zombie, "SpawnZombies");
}
else {
@ -253,7 +252,7 @@ function DemonMotherZombieArmor::AttackFunction(%datablock, %zombie, %attackFunc
if(%zombie.chargeCount == 0) {
TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %target.getPosition());
%vector = vectorNormalize(vectorSub(%target.getPosition(), %zombie.getPosition()));
%vector = vectorscale(%vector, 4000);
%vector = vectorscale(%vector, $Zombie::DemonLord_FireLunge_Thrust);
%x = Getword(%vector, 0);
%y = Getword(%vector, 1);
%z = Getword(%vector, 2);
@ -272,7 +271,7 @@ function DemonMotherZombieArmor::AttackFunction(%datablock, %zombie, %attackFunc
%zombie.attackFunction = %datablock.schedule(300, 0, "AttackFunction", %zombie, %attackFunction, %target);
}
else {
if(vectorDist(%zombie.getPosition(), %target.getPosition()) < 10) {
if(vectorDist(%zombie.getPosition(), %target.getPosition()) < $Zombie::DemonLord_FireLunge_MinimumRange) {
%p = new TracerProjectile() {
dataBlock = napalmSubExplosion;
initialDirection = "0 0 -10";
@ -328,7 +327,7 @@ function DemonMotherZombieArmor::AttackFunction(%datablock, %zombie, %attackFunc
if(%zombie.chargecount $= "") {
%zombie.chargecount = 0;
}
if(%zombie.chargecount <= 9){
if(%zombie.chargecount <= 9) {
TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %target.getPosition());
%zombie.setvelocity("0 0 10");
%zombie.chargecount++;
@ -346,7 +345,7 @@ function DemonMotherZombieArmor::AttackFunction(%datablock, %zombie, %attackFunc
%zombie.chargecount++;
%zombie.attackFunction = %datablock.schedule(400, 0, "AttackFunction", %zombie, %attackFunction, %target);
}
else if(%zombie.chargecount >= 11){
else if(%zombie.chargecount >= 11) {
%zombie.startFade(500, 0, false);
%zombie.setPosition(%zombie.attackpos);
%zombie.setvelocity(vectorscale(%zombie.attackdir, 25));

View file

@ -65,7 +65,7 @@ function ZombieArmor::armorCollisionFunction(%datablock, %zombie, %colPlayer) {
function ZombieArmor::AI(%datablock, %zombie) {
//Normal zombies do not employ any "AI" other than target and move, fork off to main move function
%datablock.Move(%zombie);
%zombie.moveloop = %datablock.Move(%zombie);
}
function ZombieArmor::Move(%datablock, %zombie) {
@ -80,16 +80,7 @@ function ZombieArmor::Move(%datablock, %zombie) {
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());
}
}
TWM2Lib_Zombie_Core("playZAudio", %zombie, 100, 40);
%vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %closestClient.getPosition());
if(Game.CheckModifier("SuperLunge") == 1) {

View file

@ -128,16 +128,7 @@ function RapierZombieArmor::move(%datablock, %zombie) {
%Zombie.mountImage(ZWingaltImage, 3);
%Zombie.mountImage(ZWingaltImage2, 4);
}
%chance = (getrandom() * 20);
if(%chance >= 19) {
%chance = (getRandom() * 12);
if(%chance <= 11) {
serverPlay3d("ZombieMoan", %zombie.getWorldBoxCenter());
}
else {
serverPlay3d("ZombieHOWL", %zombie.getWorldBoxCenter());
}
}
TWM2Lib_Zombie_Core("playZAudio", %zombie, 20, 12);
if(%zombie.iscarrying == 1) {
%vector = vectorscale(%zombie.getForwardVector(), (%zombie.speed / 2));
%vector = getword(%vector, 0)@" "@getword(%vector, 1)@" "@($Zombie::RapierUpwardScaling * 1.5);

View file

@ -132,16 +132,7 @@ function RavagerZombieArmor::Move(%datablock, %zombie) {
%pos = %zombie.getWorldBoxCenter();
%upVec = "250";
//moanStuff
%chance = (getrandom() * 50);
if(%chance >= 49) {
%chance = (getRandom() * 12);
if(%chance <= 11) {
serverPlay3d("ZombieMoan", %zombie.getWorldBoxCenter());
}
else {
serverPlay3d("ZombieHOWL", %zombie.getWorldBoxCenter());
}
}
TWM2Lib_Zombie_Core("playZAudio", %zombie, 250, 40);
//Determine target location
if(%zombie.ambushing) {
%vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %zombie.ambushPosition);

View file

@ -1,3 +1,5 @@
$TWM2::ArmorHasCollisionFunction[ShifterZombieArmor] = true;
datablock PlayerData(ShifterZombieArmor) : LightMaleHumanArmor {
runForce = 60.20 * 90;
runEnergyDrain = 0.0;
@ -34,63 +36,87 @@ datablock PlayerData(ShifterZombieArmor) : LightMaleHumanArmor {
max[Grenade] = 0;
};
function ShifterZombiemovetotarget(%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;
function ShifterZombieArmor::armorCollisionFunction(%datablock, %zombie, %colPlayer) {
if(!isObject(%zombie) || %zombie.getState() $= "dead") {
return;
}
%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(%closestDistance <= $zombie::lungDist && %zombie.canjump == 1)
%fmultiplier = (%fmultiplier * 4);
%vector = vectorscale(%vector, %Fmultiplier);
%upvec = "150";
//tis shift timez :)
if(%closestDistance > 200 || (%zombie.getVelocity() == 0 && !%zombie.RecentShift)) {
%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(10500, 0, "eval", ""@%zombie@".RecentShift=0;");
}
if(%closestDistance <= $zombie::lungDist && %zombie.canjump == 1){
%upvec = %upvec * 2;
%zombie.canjump = 0;
schedule(1500, %zombie, "Zsetjump", %zombie);
if(!isObject(%colPlayer) || %colPlayer.getState() $= "dead") {
return;
}
%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, "ShifterZombiemovetotarget", %zombie);
//Check to make sure we're not hitting another zombie / boss
if(%colPlayer.isBoss || %colPlayer.isZombie || %colPlayer.rapierShield) {
return;
}
//Damage.
%causeInfect = %zombie.damage_infectOnTouch;
%baseDamage = %zombie.damage_amountOnTouch;
%multiplier = %zombie.damage_alreadyInfectedMultiplier;
%total = %colPlayer.infected ? (%baseDamage * %multiplier) : %baseDamage;
%pushVector = vectorscale(%colPlayer.getvelocity(), 100);
%colPlayer.applyimpulse(%colPlayer.getposition(), %pushVector);
if(%causeInfect) {
%colPlayer.Infected = 1;
%colPlayer.InfectedLoop = schedule(10, %colPlayer, "TWM2Lib_Zombie_Core", "InfectLoop", %colPlayer, "impact");
}
%colPlayer.damage(0, %colPlayer.getPosition(), %total, $DamageType::Zombie);
}
function ShifterZombieArmor::AI(%datablock, %zombie) {
//Shifter zombies do not employ any "AI" other than target and move, fork off to main move function
%zombie.moveloop = %datablock.Move(%zombie);
}
function ShifterZombieArmor::Move(%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;
}
TWM2Lib_Zombie_Core("playZAudio", %zombie, 100, 40);
%vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %closestClient.getPosition());
if(%closestDistance <= $Zombie::LungeDistance && %zombie.canjump == 1) {
%vector = vectorScale(%vector, 4);
}
%vector = vectorScale(%vector, %zombie.speed);
%upvec = "150";
//tis shift timez :)
if(%closestDistance > $Zombie::Shifter_Teleport_MaximumRange || (%zombie.getVelocity() == 0 && !%zombie.RecentShift)) {
%zombie.setMoveState(true);
%zombie.startFade($Zombie::Shifter_Teleport_PrepTime, 0, true);
%zombie.schedule($Zombie::Shifter_Teleport_PrepTime + 100, "SetPosition", VectorAdd(%closestClient.getPosition(), vectorAdd("0 0 3", TWM2Lib_MainControl("getRandomPosition", "5\t1"))));
%zombie.startFade($Zombie::Shifter_Teleport_PrepTime + 250, 0, false);
%zombie.schedule($Zombie::Shifter_Teleport_PrepTime + 350, setMoveState, false);
TWM2Lib_Zombie_Core("setZFlag", %zombie, "recentShift", 1);
schedule($Zombie::Shifter_Teleport_Cooldown, 0, TWM2Lib_Zombie_Core, "setZFlag", %zombie, "recentShift", 0);
}
if(%closestDistance <= $Zombie::LungeDistance && %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.updateTimeFrequency, %zombie, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %zombie);
}
%zombie.moveloop = %datablock.schedule(%zombie.updateTimeFrequency, %datablock, "Move", %zombie);
}