Sniper Zombie, Bug Fixes

Upgraded the sniper zombie to the new AI system, fixed a few logic
errors in the ZombieCore file.
This commit is contained in:
Robert Fritzen 2017-12-23 13:16:46 -06:00
parent 0ad6bd6eba
commit f5160868da
5 changed files with 187 additions and 134 deletions

View file

@ -99,6 +99,11 @@ PLEASE NOTE: I've moved all old changelogs into the version_history folder. This
* 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
* Sniper
* The sniper zombie is now armed with two new weapons.
* The first is an acid sniper rifle which infects players on striking
* The second is a rapid fire sidearm that the sniper will use when targets move too close
* Reduced the health of Sniper Zombies from 40 (4.0) to 25 (2.5)
* 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

@ -513,6 +513,7 @@ $ZArmor[1, 2] = "Rav\t0\tRavenger Zombie\tAbility: Jet Key To Speed Forward/Lung
$ZArmor[2, 2] = "Lord\t0\tZombie Lord\tAbilities: Jet Key To Fire, Mine Key To Lift";
$ZArmor[3, 2] = "Demon\t0\tDemon Zombie\tAbility: Jet Key To Throw Fireball";
$ZArmor[4, 2] = "Rap\t1\tAir Rapier Zombie\tAbility: Jet Key Flies";
$ZArmor[5, 2] = "VolRav\t1\tVolatile Ravenger Zombie\tAbility: Jet Key To Detonate C4";
$ZArmor[0, 3] = "Norm\t0\tNormal Zombie\tAbility: Jet Key To Lunge";
$ZArmor[1, 3] = "Rav\t0\tRavenger Zombie\tAbility: Jet Key To Speed Forward/Lunge";
@ -521,7 +522,7 @@ $ZArmor[3, 3] = "Demon\t0\tDemon Zombie\tAbility: Jet Key To Throw Fireball";
$ZArmor[4, 3] = "Rap\t0\tAir Rapier Zombie\tAbility: Jet Key Flies";
$ZArmor[5, 3] = "VolRav\t0\tVolatile Ravenger Zombie\tAbility: Jet Key To Detonate C4";
$ZArmor[6, 3] = "UDem\t1\tUltra Demon Zombie\tAbility: Jet Key To Fire, Mine To Charge Forward";
$ZArmor[7, 3] = "Wraith\t1\tWraith Spec-Ops Zombie\tAbility: Jet Key To Charge, Armed with MP26-CMDO";
//$ZArmor[7, 3] = "Wraith\t1\tWraith Spec-Ops Zombie\tAbility: Jet Key To Charge, Armed with MP26-CMDO";
$ZArmor[0, 4] = "Norm\t0\tNormal Zombie\tAbility: Jet Key To Lunge";
$ZArmor[1, 4] = "Rav\t0\tRavenger Zombie\tAbility: Jet Key To Speed Forward/Lunge";
@ -530,8 +531,8 @@ $ZArmor[3, 4] = "Demon\t0\tDemon Zombie\tAbility: Jet Key To Throw Fireball";
$ZArmor[4, 4] = "Rap\t0\tAir Rapier Zombie\tAbility: Jet Key Flies";
$ZArmor[5, 4] = "VolRav\t0\tVolatile Ravenger Zombie\tAbility: Jet Key To Detonate C4";
$ZArmor[6, 4] = "UDem\t0\tUltra Demon Zombie\tAbility: Jet Key To Fire, Mine To Charge Forward";
$ZArmor[7, 4] = "Wraith\t0\tWraith Spec-Ops Zombie\tAbility: Jet Key To Charge, Armed with MP26-CMDO";
$ZArmor[8, 4] = "Rog\t1\tGeneral Rog\tAbilities: Jet Key To fire zMG42, Shielded, Armed with BoV";
//$ZArmor[7, 4] = "Flareguide\t0\tFist of Vengeance Flareguide\tAbility: Armed with the Bursting NLS-22 Rifle, Grenade to Vanish";
//$ZArmor[8, 4] = "Rog\t1\tGeneral Rog\tAbilities: Jet Key To fire zMG42, Shielded, Armed with BoV";
//Score Hud
$ScoreHudMaxVisible = 19;

View file

@ -1,3 +1,24 @@
//**********************************************
//**********************************************
// Player Zombie Functioning
//
// Updated TWM2 3.9.2
// Cleaned up all of the functions and converted it into a library style
// system to reduce the function count
//**********************************************
//**********************************************
function TWM2Lib_Zombie_PlayerFunctions(%functionName, %arg1, %arg2, %arg3, %arg4) {
switch$(strlwr(%functionName)) {
case "zombieattackimpulse":
case "makepersonzombie":
default:
error("TWM2Lib_Zombie_PlayerFunctions(): Unknown function name "@%functionName@" sent to call.");
}
}
function makePersonHumanFZomb(%trans, %client){
%client.player.delete();
%player = new Player() {

View file

@ -105,6 +105,22 @@ $Zombie::Shifter_Teleport_Cooldown = 12500;
//$Zombie::Summoner_Cooldown: The cooldown of the summoner zombie's summon ability
$Zombie::Summoner_Cooldown = 25000;
//$Zombie::Sniper_MaximumEngageRange: The maximum range at which the sniper zombie will fire at.
// NOTE: If the target is outside of this range, the sniper will begin "consideration" to look for a new target
$Zombie::Sniper_MaximumEngageRange = 450;
//$Zombie::Sniper_PreferedDistanceFromTarget: The range at which the sniper zombie will move up to try to reach
$Zombie::Sniper_PreferedDistanceFromTarget = 300;
//$Zombie::Sniper_SidearmRange: The range at which the sniper zombie engages CQC combat with it's sidearm
$Zombie::Sniper_SidearmRange = 50;
//$Zombie::Sniper_RifleCooldown: The reload time of the sniper zombie's rifle (MS)
$Zombie::Sniper_RifleCooldown = 7000;
//$Zombie::Sniper_SidearmBurstCount: The amount of shots in a sidearm burst
$Zombie::Sniper_SidearmBurstCount = 10;
//$Zombie::Sniper_SidearmBurstTime: The amount of time to fire off the full burst
$Zombie::Sniper_SidearmBurstTime = 600;
//$Zombie::Sniper_SidearmCooldown: The reload time of the sniper zombie's sidearm (MS)
$Zombie::Sniper_SidearmCooldown = 5000;
//MISC Globals, Do not edit.
$Zombie::killpoints = 5;
$Zombie::RogThread = "cel1";
@ -173,7 +189,7 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
%vec = %rx @ " " @ %ry @ " " @ 0;
%arg1.direction = vectorNormalize(%vec);
%arg1.Mnum = getRandom(1, 20);
%arg1.zombieRmove = schedule($Zombie::SpeedUpdateTime, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1);
%arg1.zombieRmove = schedule(%arg1.updateTimeFrequency, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1);
//zrandommoveloop(%zombie): Moves the zombies around in a random direction
case "zrandommoveloop":
@ -193,10 +209,10 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
%vector = vectorScale(%vec, %speed);
%arg1.applyImpulse(%arg1.direction, %vector);
%arg1.Mnum -= 1;
%arg1.zombieRmove = schedule($Zombie::SpeedUpdateTime, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1);
%arg1.zombieRmove = schedule(%arg1.updateTimeFrequency, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1);
}
else {
%arg1.zombieRmove = schedule($Zombie::SpeedUpdateTime, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1);
%arg1.zombieRmove = schedule(%arg1.updateTimeFrequency, %arg1, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %arg1);
}
//cureInfection(%player): Cures the zombie infection
@ -304,6 +320,8 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
%arg1.firingWeapon = %arg3;
case "canfireweapon":
%arg1.canFireWeapon = %arg3;
case "canaltfire":
%arg1.canAltFire = %arg3;
}
//lookForTarget(%zombie, [%pilot], [%groundVeh]): Identify the closest target, and the distance to that target
@ -560,6 +578,8 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
%zombie.mountImage(ZSniperImage1, 4);
%zombie.mountImage(ZSniperImage2, 5);
%zombie.mountImage(ZSniperImage3, 6);
%zombie.canFireWeapon = 1;
%zombie.canAltFire = 1;
//Ultra-Demon Zombie
case 12:
@ -616,7 +636,7 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
%zombie.mountImage(ZdummyslotImg, 4);
//Flareguide Sniper Zombie (Mini-Boss)
case 11:
case 18:
%zombie = new player(){
Datablock = "FlareguideSniperZombieArmor";
};

View file

@ -63,16 +63,52 @@ function SniperZombieArmor::AI(%datablock, %zombie) {
return;
}
%pos = %zombie.getWorldBoxCenter();
//Target update.
if(%zombie.hadTarget) {
if(!isObject(%zombie.targetPlayer) || %zombie.targetPlayer.getState() $= "dead") {
//Target is down for the count, let's move on.
%zombie.hasTarget = 0;
%zombie.CQCTarget = 0;
%zombie.reallyFarTarget = 0;
%zombie.targetPlayer = 0;
}
}
//Do I have a target, but it's far out (IE: Running or Pilot?)
if(%zombie.hasTarget && %zombie.reallyFarTarget) {
//Throw a 1 in 25 chance to abort and re-search
if(getRandom(1, 25) == 19) {
%zombie.hasTarget = 0;
%zombie.targetPlayer = 0;
%zombie.CQCTarget = 0;
%zombie.reallyFarTarget = 0;
}
}
//Are there any targets?
if(!%zombie.hasTarget) {
%preferSniper = getRandom(1, 10);
if(%preferSniper > 3) {
if(%preferSniper > 4) {
for(%i = 0; %i < ClientGroup.getCount(%i); %i++) {
%check = ClientGroup.getObject(%i);
if(isObject(%check.player) && %check.player.getState() !$= "dead") {
//Check their weapon
%w = %check.player.getMountedImage($WeaponSlot).getName();
if(!strStr(strlwr(%w), "sniper")) {
//Bingo!
%zombie.hasTarget = 1;
%zombie.targetPlayer = %check.player;
break;
}
}
}
//No enemy snipers found... Look for a new target.
if(!%zombie.hasTarget) {
%closestClient = TWM2Lib_Zombie_Core("lookForTarget", %zombie);
%closestDistance = getWord(%closestClient, 1);
if(isObject(%closestClient.player) && %closestClient.player.getState() !$= "dead") {
%zombie.hasTarget = 1;
%zombie.targetPlayer = %closestClient.player;
}
}
}
else {
%closestClient = TWM2Lib_Zombie_Core("lookForTarget", %zombie);
@ -83,8 +119,48 @@ function SniperZombieArmor::AI(%datablock, %zombie) {
}
}
}
%zombie.moveloop = %datablock.Move(%zombie);
//Do I have a target?
if(%zombie.hasTarget) {
//Check the distance...
%tPos = %zombie.targetPlayer.getPosition();
%dist = vectorDist(%pos, %tPos);
if(%dist < $Zombie::Sniper_SidearmRange) {
//Target is getting into sidearm range... engage close range attacks
%zombie.reallyFarTarget = 0;
%zombie.CQCTarget = 1;
%datablock.Move(%zombie);
if(%zombie.canAltFire) {
TWM2Lib_Zombie_Core("setZFlag", %zombie, "canAltFire", 0);
schedule($Zombie::Sniper_RifleCooldown, 0, TWM2Lib_Zombie_Core, "setZFlag", %zombie, "canAltFire", 1);
for(%i = 0; %i < $Zombie::Sniper_SidearmBurstCount; %i++) {
%timeDelay = ($Zombie::Sniper_SidearmBurstTime / $Zombie::Sniper_SidearmBurstCount) * %i;
%datablock.schedule(%timeDelay, "zFire_Alternate", %zombie);
}
}
}
else if(%dist < $Zombie::Sniper_MaximumEngageRange && %dist > $Zombie::Sniper_SidearmRange) {
//Target is in Sniper Range... engage.
%zombie.reallyFarTarget = 0;
%zombie.CQCTarget = 0;
if(vectorDist(%pos, %tPos) > $Zombie::Sniper_PreferedDistanceFromTarget) {
//I'm a bit far out myself, let's move up while we engage.
%datablock.Move(%zombie);
}
if(%zombie.canFireWeapon) {
TWM2Lib_Zombie_Core("setZFlag", %zombie, "canFireWeapon", 0);
schedule($Zombie::Sniper_RifleCooldown, 0, TWM2Lib_Zombie_Core, "setZFlag", %zombie, "canFireWeapon", 1);
%datablock.zFire(%zombie);
}
}
else {
//Target's a bit too far out, let's move up, but flag our AI to begin thinking about a new target
%zombie.reallyFarTarget = 1;
%zombie.CQCTarget = 0;
%datablock.Move(%zombie);
}
}
//No targets... Let's just wait.
%zombie.aiLoop = %datablock.schedule(%zombie.updateTimeFrequency, "AI", %zombie);
}
function SniperZombieArmor::Move(%datablock, %zombie) {
@ -92,46 +168,63 @@ function SniperZombieArmor::Move(%datablock, %zombie) {
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(Game.CheckModifier("SuperLunge") == 1) {
%ld = $Zombie::LungeDistance * 5;
}
else {
%ld = $Zombie::LungeDistance;
}
if(%closestDistance <= %ld && %zombie.canjump == 1) {
%vector = vectorScale(%vector, 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);
}
%tPos = %zombie.targetPlayer.getPosition();
%upVec = "250";
//Are we fighting in close quarters or not?
if(%zombie.CQCTarget) {
%zombie.setVelocity("0 0 0");
//FaceTarget(%zombie, %target);
TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %tPos);
%vector = vectorNormalize(vectorSub(%tPos, %zombie.getPosition()));
%vector = vectorscale(%vector, %zombie.speed);
%x = Getword(%vector, 0);
%y = Getword(%vector, 1);
%z = Getword(%vector, 2);
if(%z >= 600) {
%upvec = (%upvec * 5);
}
%nv1 = %y;
%nv2 = (%x * -1);
%vector = %nv1@" "@%nv2@" 0";
%zombie.applyImpulse(%zombie.getPosition(), %vector);
}
else {
%vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %tPos);
//Scale to speed
%vector = vectorScale(%vector, %zombie.speed);
%x = getWord(%vector, 0);
%y = getWord(%vector, 1);
%vector = %x@" "@%y@" "@%upvec;
%zombie.applyImpulse(%pos, %vector);
%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, "Move", %zombie);
}
function SniperZombieArmor::zFire(%datablock, %zombie) {
%target = %zombie.targetPlayer;
%num = getRandom(250, 1000);
%vec = vectorsub(VectorAdd(%target.getPosition(), "0 0 2.2"), %zombie.getMuzzlePoint(4));
%accuracy = (vectorlen(%vec) / %num);
%vec = vectoradd(%vec, vectorscale(%target.getvelocity(), %accuracy));
%p = new TracerProjectile() {
dataBlock = SniperZombieAcidShot;
initialDirection = %vec;
initialPosition = %zombie.getMuzzlePoint(4);
sourceObject = %zombie;
sourceSlot = 4;
};
ServerPlay3D(CentaurArtilleryFireSound, %zombie.getPosition());
}
function SniperZombieArmor::zFire_Alternate(%datablock, %zombie) {
%target = %zombie.targetPlayer;
%num = getRandom(250, 1000);
%vec = vectorsub(VectorAdd(%target.getPosition(), "0 0 1"), %zombie.getMuzzlePoint(4));
%accuracy = (vectorlen(%vec) / %num);
%vec = vectoradd(%vec, vectorscale(%target.getvelocity(), %accuracy));
%p = new TracerProjectile() {
dataBlock = SniperZombieAcidSidearmShot;
initialDirection = %vec;
initialPosition = %zombie.getMuzzlePoint(4);
sourceObject = %zombie;
sourceSlot = 4;
};
ServerPlay3D(CentaurArtilleryFireSound, %zombie.getPosition());
}
//*****************************************************************
@ -163,93 +256,6 @@ datablock PlayerData(FlareguideSniperZombieArmor) : SniperZombieArmor {
max[Grenade] = 0;
};
function SniperZombiemovetotarget(%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(%closestDistance < 50) { //runz0rs
%TPos = %closestClient.getPosition();
%tvel = %closestclient.getvelocity();
%vec = vectorsub(%tpos,%pos);
%dist = vectorlen(%vec);
%velpredict = vectorscale(%tvel,(%dist / 50));
%vector = vectoradd(%vec,%velpredict);
%vector = vectornormalize(%vector);
%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
%zombie.applyImpulse(%pos, %finalVec);
}
else {
if(%zombie.hastarget != 1 && %closestdistance >= 50){
SniperZombieFire(%zombie,%closestclient);
%zombie.canjump = 0;
schedule(4000, %zombie, "Zsetjump", %zombie);
}
if(%zombie.hastarget != 1){
serverPlay3d("ZombieHOWL",%zombie.getWorldBoxCenter());
%zombie.hastarget = 1;
}
%chance = (getrandom() * 20);
if(%chance >= 19)
serverPlay3d("ZombieMoan",%zombie.getWorldBoxCenter());
%vector = ZgetFacingDirection(%zombie,%closestClient,%pos);
if (%closestdistance >= 50 && %zombie.canjump == 1){
SniperZombieFire(%zombie,%closestclient);
%zombie.canjump = 0;
schedule(4000, %zombie, "Zsetjump", %zombie);
}
if(%closestdistance > 175) { //only move toward my foe, if he is too
%vector = vectorscale(%vector, $Zombie::DForwardSpeed); //far away
%upvec = "150";
%x = Getword(%vector,0);
%y = Getword(%vector,1);
%z = Getword(%vector,2);
if(%z >= ($Zombie::DForwardSpeed / 3 * 2))
%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, "SniperZombiemovetotarget", %zombie);
}
function SniperZombieFire(%zombie,%closestclient){
%num = getRandom(250, 1000);
%vec = vectorsub(VectorAdd(%closestclient.getPosition(), "0 0 2.2"),%zombie.getMuzzlePoint(4));
%accuracy = (vectorlen(%vec) / %num);
%vec = vectoradd(%vec, vectorscale(%closestclient.getvelocity(), %accuracy));
%p = new TracerProjectile() { //TWM2 Sniper zombies use ALSWP Snipers :P
dataBlock = SniperZombieAcidShot;
initialDirection = %vec;
initialPosition = %zombie.getMuzzlePoint(4);
sourceObject = %zombie;
sourceSlot = 4;
};
ServerPlay3D(ALSWPFireSound, %zombie.getPosition());
}
function FlareguideSniperZombieAcidShot::onExplode(%data, %proj, %pos, %mod) {
Parent::OnExplode(%data, %proj, %pos, %mod);
//Create the mini-pulses