mirror of
https://github.com/Ragora/T2-ACCM.git
synced 2026-01-20 03:14:44 +00:00
1665 lines
48 KiB
C#
1665 lines
48 KiB
C#
//----------------------------------------------
|
|
// zombie.cs
|
|
// Zombie AI Code
|
|
//==============================================
|
|
function ZcreateLoop(%obj)
|
|
{
|
|
if(isObject(%obj))
|
|
{
|
|
if(%obj.timedout == 0){
|
|
if((%obj.numZ <= 2 || %obj.numZ $= "") && (ZombieGroup.getCount() < $Host::MaxZombies || $Host::MaxZombies == -1)){
|
|
ZPCreateZombie(%obj);
|
|
if(%obj.numZ $= "")
|
|
%obj.numZ = 0;
|
|
%obj.numZ++;
|
|
%obj.timedout = 1;
|
|
schedule(10000, %obj, "TimedInF", %obj);
|
|
}
|
|
}
|
|
%obj.ZCLoop = schedule(2000, 0, "ZcreateLoop", %obj);
|
|
}
|
|
}
|
|
|
|
function TimedInF(%obj){
|
|
%obj.timedout = 0;
|
|
}
|
|
|
|
//this is for when a ZSpawn spawns a zombie
|
|
function ZPCreateZombie(%obj){
|
|
%Cpos = vectorAdd(%obj.getposition() ,%obj.getUpvector());
|
|
if(%obj.Ztype $= ""){
|
|
%obj.ZType = 1;
|
|
}
|
|
if(%obj.ZType == 1){
|
|
%Zombie = new player(){
|
|
Datablock = "ZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Zombie");
|
|
%Cpos = vectoradd(vectoradd(vectorscale(%obj.getUpvector(),1.15),"0 0 -1.15"),%obj.getposition());
|
|
}
|
|
else if(%obj.ZType == 2){
|
|
%Zombie = new player(){
|
|
Datablock = "FZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Ravenger Zombie");
|
|
%Cpos = vectoradd(vectoradd(vectorscale(%obj.getUpvector(),1.15),"0 0 -1.15"),%obj.getposition());
|
|
}
|
|
else if(%obj.ZType == 3){
|
|
%Zombie = new player(){
|
|
Datablock = "LordZombieArmor";
|
|
};
|
|
applyskin(%zombie,'ZLord',"Zombie Lord");
|
|
%Cpos = vectoradd(vectoradd(vectorscale(%obj.getUpvector(),2.4),"0 0 -2.4"),%obj.getposition());
|
|
%Zombie.mountImage(ZHead, 3);
|
|
%Zombie.mountImage(ZBack, 4);
|
|
%Zombie.mountImage(ZDummyslotImg, 5);
|
|
%Zombie.mountImage(ZDummyslotImg2, 6);
|
|
%zombie.firstFired = 0;
|
|
%zombie.canmove = 1;
|
|
}
|
|
else if(%obj.ZType == 4){
|
|
%Zombie = new player(){
|
|
Datablock = "DemonZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Demon Zombie");
|
|
%zombie.mountImage(ZdummyslotImg, 4);
|
|
%Cpos = vectoradd(vectoradd(vectorscale(%obj.getUpvector(),1.3),"0 0 -1.3"),%obj.getposition());
|
|
}
|
|
else if(%obj.ZType == 5){
|
|
%Zombie = new player(){
|
|
Datablock = "RapierZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Rapier Zombie");
|
|
%Zombie.mountImage(ZWingImage, 3);
|
|
%Zombie.mountImage(ZWingImage2, 4);
|
|
%zombie.setActionThread("scoutRoot",true);
|
|
%Cpos = vectoradd(vectoradd(vectorscale(%obj.getUpvector(),1),"0 0 -0.6"),%obj.getposition());
|
|
}
|
|
else if(%obj.ZType == 6){
|
|
%Cpos = vectoradd(vectoradd(vectorscale(%obj.getUpvector(),1.15),"0 0 -1.15"),%obj.getposition());
|
|
%Zombie = DemonMotherCreate(%Cpos);
|
|
}
|
|
|
|
%zombie.type = %obj.Ztype;
|
|
%Zombie.setTransform(%Cpos);
|
|
%Zombie.team = 0;
|
|
%zombie.HasCP = 1;
|
|
if(%obj.spawnTypeset == 1)
|
|
%obj.numZ = 3;
|
|
else
|
|
%zombie.CP = %obj;
|
|
AddToZombieGroup(%Zombie);
|
|
if(%obj.ZType != 6)
|
|
{
|
|
%zombie.canjump = 1;
|
|
%zombie.hastarget = 1;
|
|
schedule(1000, %zombie, "ZombieLookforTarget", %zombie);
|
|
}
|
|
}
|
|
|
|
//This is for creation of a zombie at a location using the console
|
|
function StartAZombie(%pos, %type){
|
|
if(ZombieGroup.getCount >= $Host::MaxZombies && $Host::MaxZombies != -1)
|
|
{
|
|
error("StartAZombie: Cannot spawn. There are too many zombies on the server.");
|
|
return;
|
|
}
|
|
|
|
if(%Type == 1){
|
|
%Zombie = new player(){
|
|
Datablock = "ZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Zombie");
|
|
}
|
|
if(%Type == 2){
|
|
%Zombie = new player(){
|
|
Datablock = "FZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Ravenger Zombie");
|
|
}
|
|
if(%Type == 3){
|
|
%Zombie = new player(){
|
|
Datablock = "LordZombieArmor";
|
|
};
|
|
applyskin(%zombie,'ZLord',"Zombie Lord");
|
|
%zombie.client = $zombie::Lclient;
|
|
%Zombie.mountImage(ZHead, 3);
|
|
%Zombie.mountImage(ZBack, 4);
|
|
%Zombie.mountImage(ZDummyslotImg, 5);
|
|
%Zombie.mountImage(ZDummyslotImg2, 6);
|
|
%zombie.firstFired = 0;
|
|
%zombie.canmove = 1;
|
|
}
|
|
if(%type == 4){
|
|
%Zombie = new player(){
|
|
Datablock = "DemonZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Demon Zombie");
|
|
%zombie.mountImage(ZdummyslotImg, 4);
|
|
}
|
|
%zombie.type = %type;
|
|
%Zombie.setTransform(%pos);
|
|
%Zombie.team = 0;
|
|
%zombie.canjump = 1;
|
|
%zombie.hastarget = 1;
|
|
AddToZombieGroup(%Zombie);
|
|
schedule(1000, %zombie, "ZombieLookforTarget", %zombie);
|
|
}
|
|
|
|
//This is for when someone is killed by a zombie and spawns a new one
|
|
function CreateZombie(%obj){
|
|
if(ZombieGroup.getCount() >= $Host::MaxZombies && $Host::MaxZombies != -1)
|
|
return;
|
|
|
|
%Cpos = %obj.getposition();
|
|
%Zombie = new player(){
|
|
Datablock = "ZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Zombie");
|
|
%Zombie.setTransform(%Cpos);
|
|
%zombie.type = 1;
|
|
%Zombie.team = 0;
|
|
%zombie.canjump = 1;
|
|
%zombie.hastarget = 1;
|
|
AddToZombieGroup(%Zombie);
|
|
schedule(1000, %zombie, "ZombieLookforTarget", %zombie);
|
|
}
|
|
|
|
function ZombieLookforTarget(%zombie)
|
|
{
|
|
if(!isObject(%zombie)) {
|
|
return;
|
|
}
|
|
|
|
if(%Zombie.getState() $= "dead") {
|
|
freeClientTarget(%zombie);
|
|
return;
|
|
}
|
|
|
|
%pos = %zombie.getposition();
|
|
%wbpos = %zombie.getworldboxcenter();
|
|
%count = ClientGroup.getCount();
|
|
%closestClient = -1;
|
|
%closestDistance = 32767;
|
|
for(%i = 0; %i < %count; %i++)
|
|
{
|
|
%cl = ClientGroup.getObject(%i);
|
|
if(isObject(%cl.player)){
|
|
%testPos = %cl.player.getWorldBoxCenter();
|
|
%distance = vectorDist(%wbpos, %testPos);
|
|
if (%distance > 0 && %distance < %closestDistance && %cl.player.isFTD != 1 && %cl.player.iszombie != 1)
|
|
{
|
|
%closestClient = %cl;
|
|
%closestDistance = %distance;
|
|
}
|
|
}
|
|
}
|
|
if(%closestClient){
|
|
if (%zombie.type == 1)
|
|
Zombiemovetotarget(%zombie,%closestClient,%closestDistance);
|
|
else if (%zombie.type == 2)
|
|
FZombiemovetotarget(%zombie,%closestClient,%closestDistance);
|
|
else if (%zombie.type == 3)
|
|
LZombiemovetotarget(%zombie,%closestClient,%closestDistance);
|
|
else if (%zombie.type == 4)
|
|
DZombiemovetotarget(%zombie,%closestClient,%closestDistance);
|
|
else if (%zombie.type == 5)
|
|
RZombiemovetotarget(%zombie,%closestClient,%closestDistance);
|
|
}
|
|
%zombie.ZombieTargeting = schedule(500, %zombie, "ZombieLookForTarget", %zombie);
|
|
}
|
|
|
|
function Zombiemovetotarget(%zombie,%closestClient,%closestDistance){
|
|
%pos = %zombie.getworldboxcenter();
|
|
%closestClient = %closestClient.Player;
|
|
if(%closestDistance <= $zombie::detectDist){
|
|
if(%zombie.hastarget != 1){
|
|
%zombie.hastarget = 1;
|
|
}
|
|
%chance = (getrandom() * 20);
|
|
if(%chance >= 19)
|
|
ZDoMoan(%zombie);
|
|
|
|
%clpos = %closestClient.getPosition();
|
|
%vector = vectorNormalize(vectorSub(%clpos, %pos));
|
|
%v1 = getword(%vector, 0);
|
|
%v2 = getword(%vector, 1);
|
|
%nv1 = %v2;
|
|
%nv2 = (%v1 * -1);
|
|
%none = 0;
|
|
%vector2 = %nv1@" "@%nv2@" "@%none;
|
|
%zombie.setRotation(fullrot("0 0 0",%vector2));
|
|
|
|
%fmultiplier = $Zombie::ForwardSpeed;
|
|
if(%closestDistance <= $zombie::lungDist && %zombie.canjump == 1)
|
|
%fmultiplier = (%fmultiplier * 4);
|
|
%vector = vectorscale(%vector, %Fmultiplier);
|
|
%upvec = "150";
|
|
if(%closestDistance <= $zombie::lungDist && %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);
|
|
}
|
|
}
|
|
|
|
function FZombiemovetotarget(%zombie,%closestClient,%closestDistance){
|
|
%pos = %zombie.getworldboxcenter();
|
|
%closestClient = %closestClient.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)
|
|
ZDoMoan(%zombie);
|
|
|
|
//Rotation stuff
|
|
%clpos = %closestClient.getPosition();
|
|
%vector = vectorNormalize(vectorSub(%clpos, %pos));
|
|
%v1 = getword(%vector, 0);
|
|
%v2 = getword(%vector, 1);
|
|
%nv1 = %v2;
|
|
%nv2 = (%v1 * -1);
|
|
%none = 0;
|
|
%vector2 = %nv1@" "@%nv2@" "@%none;
|
|
%zombie.setRotation(fullrot("0 0 0",%vector2));
|
|
|
|
//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);
|
|
}
|
|
}
|
|
|
|
function LZombiemovetotarget(%zombie,%closestClient,%closestDistance){
|
|
%pos = %zombie.getworldboxcenter();
|
|
%closestClient = %closestClient.Player;
|
|
if(%closestDistance <= $zombie::detectDist && %zombie.canmove != 0){
|
|
if(%zombie.hastarget != 1){
|
|
LZDoYell(%zombie);
|
|
%zombie.hastarget = 1;
|
|
}
|
|
%chance = (getrandom() * 20);
|
|
if(%chance >= 19)
|
|
LZDoMoan(%zombie);
|
|
|
|
%clpos = %closestClient.getPosition();
|
|
%vector = vectorNormalize(vectorSub(%clpos, %pos));
|
|
%nv2 = (getword(%vector, 0) * -1);
|
|
%nv1 = getword(%vector, 1);
|
|
%none = 0;
|
|
%vector2 = %nv1@" "@%nv2@" "@%none;
|
|
%zombie.setRotation(fullrot("0 0 0",%vector2));
|
|
if(%zombie.ATCount >= 20){
|
|
%zombie.ATCount = 0;
|
|
%zombie.nomove = 1;
|
|
%zombie.Fire = schedule(1250, %zombie, "ZFire", %zombie, %closestClient);
|
|
%zombie.Charge = schedule(500, %zombie, "ChargeEmitter", %zombie);
|
|
%zombie.chargecount = 0;
|
|
}
|
|
if(%zombie.nomove != 1) {
|
|
%fmultiplier = $Zombie::LForwardSpeed;
|
|
%upvec = "150";
|
|
if(%closestDistance <= $zombie::LKillDist && %zombie.canjump == 1){
|
|
%vec = vectoradd(%pos,vectorScale(%vector,($zombie::LkillDist - 1.6)));
|
|
%mask = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::TerrainObjectType | $TypeMasks::PlayerObjectType;
|
|
%searchResult = containerRayCast(vectoradd(%pos,vectorScale(%vector,1.6)), %vec, %mask, %zombie);
|
|
if(%searchResult){
|
|
%searchObj = getWord(%searchResult,0);
|
|
if(%searchObj $= %closestClient){
|
|
%chance = getrandom(1,5);
|
|
if(%chance == 1){
|
|
%dir = %zombie.getEyeVector();
|
|
%dir = vectornormalize(getword(%dir,0)@" "@getword(%dir,1)@" 0");
|
|
%dir = vectoradd(vectorscale(%dir,7500),"0 0 1000");
|
|
%closestclient.applyimpulse(%clpos,%dir);
|
|
%closestclient.damage(0, %clpos, 0.8, $DamageType::ZombieL);
|
|
}
|
|
else{
|
|
%zombie.setvelocity("0 0 0");
|
|
%zombie.canjump = 0;
|
|
schedule(1000, %zombie, "Zsetjump", %zombie);
|
|
Llifttarget(%zombie,%closestclient,0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(%closestDistance <= ($zombie::LKillDist + $zombie::lungDist)){
|
|
%zombie.setvelocity("0 0 0");
|
|
%fmultiplier = (%fmultiplier * 2.5);
|
|
}
|
|
%vector = vectorscale(%vector, %Fmultiplier);
|
|
%x = Getword(%vector,0);
|
|
%y = Getword(%vector,1);
|
|
%z = Getword(%vector,2);
|
|
if(%z >= 4000)
|
|
%upvec = (%upvec * 5);
|
|
%vector = %x@" "@%y@" "@%upvec;
|
|
%zombie.applyImpulse(%pos, %vector);
|
|
%zombie.ATCount++;
|
|
}
|
|
}
|
|
else if(%zombie.hastarget == 1 && %zombie.canmove != 0){
|
|
%zombie.hastarget = 0;
|
|
%zombie.zombieRmove = schedule(100, %zombie, "ZSetRandomMove", %zombie);
|
|
}
|
|
}
|
|
|
|
function DZombiemovetotarget(%zombie,%closestClient,%closestDistance){
|
|
%pos = %zombie.getworldboxcenter();
|
|
%closestClient = %closestClient.Player;
|
|
if(%closestDistance <= $zombie::detectDist){
|
|
if(%zombie.hastarget != 1 && %closestdistance >= 10 && %closestdistance <= 150){
|
|
DzombieFire(%zombie,%closestclient);
|
|
%zombie.canjump = 0;
|
|
schedule(4000, %zombie, "Zsetjump", %zombie);
|
|
}
|
|
if(%zombie.hastarget != 1){
|
|
LZDoYell(%zombie);
|
|
%zombie.hastarget = 1;
|
|
}
|
|
%chance = (getrandom() * 20);
|
|
if(%chance >= 19)
|
|
LZDoMoan(%zombie);
|
|
|
|
%clpos = %closestClient.getPosition();
|
|
%vector = vectorNormalize(vectorSub(%clpos, %pos));
|
|
%v1 = getword(%vector, 0);
|
|
%v2 = getword(%vector, 1);
|
|
%nv1 = %v2;
|
|
%nv2 = (%v1 * -1);
|
|
%none = 0;
|
|
%vector2 = %nv1@" "@%nv2@" "@%none;
|
|
%zombie.setRotation(fullrot("0 0 0",%vector2));
|
|
|
|
if (%closestdistance >= 10 && %closestdistance <= 150 && %zombie.canjump == 1){
|
|
DzombieFire(%zombie,%closestclient);
|
|
%zombie.canjump = 0;
|
|
schedule(4000, %zombie, "Zsetjump", %zombie);
|
|
return;
|
|
}
|
|
%vector = vectorscale(%vector, $Zombie::DForwardSpeed);
|
|
%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);
|
|
}
|
|
}
|
|
|
|
function RZombiemovetotarget(%zombie,%closestClient,%closestDistance){
|
|
%pos = %zombie.getworldboxcenter();
|
|
%zombie.setActionThread("scoutRoot",true);
|
|
%closestClient = %closestClient.Player;
|
|
if(%closestDistance <= $zombie::detectDist){
|
|
if(%zombie.wingset == 1){
|
|
%zombie.wingset = 0;
|
|
%Zombie.mountImage(ZWingImage, 3);
|
|
%Zombie.mountImage(ZWingImage2, 4);
|
|
}
|
|
else{
|
|
%zombie.wingset = 1;
|
|
%Zombie.mountImage(ZWingaltImage, 3);
|
|
%Zombie.mountImage(ZWingaltImage2, 4);
|
|
}
|
|
%chance = (getrandom() * 20);
|
|
if(%chance >= 19)
|
|
ZDoMoan(%zombie);
|
|
if(%zombie.iscarrying == 1){
|
|
%vector = vectorscale(%zombie.getForwardVector(),($Zombie::RForwardSpeed / 2));
|
|
%vector = getword(%vector, 0)@" "@getword(%vector, 1)@" "@($zombie::Rupvec * 1.5);
|
|
%zombie.applyImpulse(%zombie.getposition(), %vector);
|
|
return;
|
|
}
|
|
|
|
%clpos = %closestClient.getWorldBoxCenter();
|
|
%vector = vectorNormalize(vectorSub(%clpos, %pos));
|
|
%v1 = getword(%vector, 0);
|
|
%v2 = getword(%vector, 1);
|
|
%nv1 = %v2;
|
|
%nv2 = (%v1 * -1);
|
|
%none = 0;
|
|
%vector2 = %nv1@" "@%nv2@" "@%none;
|
|
%zombie.setRotation(fullrot("0 0 0",%vector2));
|
|
|
|
%z = Getword(%vector,2);
|
|
%spd = vectorLen(%zombie.getVelocity());
|
|
%fallpoint = 0.05 - (%spd / 630);
|
|
if(%closestdistance <= 15 || %z > (0.25 + %fallpoint) || %z < (-1 * (0.25 + %fallpoint))){
|
|
if(%z < 0)
|
|
%upvec = ($zombie::Rupvec * (%z - (%spd / 130)));
|
|
if(%z >= 0)
|
|
%upvec = ($zombie::Rupvec * (%z + 1));
|
|
if(%spd <= 5)
|
|
%vector = vectorScale(%vector,3);
|
|
}
|
|
else{
|
|
%upvec = $zombie::Rupvec * (%z + 1.2);
|
|
%spdmod = 1;
|
|
}
|
|
if(%z < 0)
|
|
%z = %z * -1;
|
|
|
|
%Zz = getWord(%zombie.getVelocity(),2);
|
|
if(%Zz <= -40){
|
|
%result = containerRayCast(%pos, vectoradd(%pos,vectorScale("0 0 1",%Zz * 2)), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, %zombie);
|
|
if(%result)
|
|
%upvec = $zombie::Rupvec * 5;
|
|
}
|
|
|
|
%vector = vectorscale(%vector, ($Zombie::RForwardSpeed * (1 - %z)));
|
|
%x = Getword(%vector,0);
|
|
%y = Getword(%vector,1);
|
|
%vector = %x@" "@%y@" "@%upvec;
|
|
%zombie.applyImpulse(%pos, %vector);
|
|
}
|
|
}
|
|
|
|
function ZDoMoan(%zombie){
|
|
%chance = (getRandom() * 12);
|
|
if(%chance <= 11)
|
|
serverPlay3d("ZombieMoan",%zombie.getWorldBoxCenter());
|
|
else
|
|
serverPlay3d("ZombieHOWL",%zombie.getWorldBoxCenter());
|
|
}
|
|
|
|
function LZDoMoan(%zombie){
|
|
serverPlay3d("ZombieMoan",%zombie.getWorldBoxCenter());
|
|
}
|
|
|
|
function LZDoYell(%zombie){
|
|
serverPlay3d("ZombieHOWL",%zombie.getWorldBoxCenter());
|
|
}
|
|
|
|
function Zsetjump(%zombie){
|
|
%zombie.canjump = 1;
|
|
}
|
|
|
|
function ChargeEmitter(%zombie){
|
|
if(!isobject(%zombie))
|
|
return;
|
|
if(%zombie.chargecount >= 2){
|
|
%charge2 = new ParticleEmissionDummy()
|
|
{
|
|
position = %zombie.getMuzzlePoint(6);
|
|
dataBlock = "defaultEmissionDummy";
|
|
emitter = "FlameEmitter";
|
|
};
|
|
MissionCleanup.add(%charge2);
|
|
%charge2.schedule(100, "delete");
|
|
}
|
|
if(%zombie.chargecount <= 7){
|
|
%charge = new ParticleEmissionDummy()
|
|
{
|
|
position = %zombie.getMuzzlePoint(5);
|
|
dataBlock = "defaultEmissionDummy";
|
|
emitter = "FlameEmitter";
|
|
};
|
|
MissionCleanup.add(%charge);
|
|
%charge.schedule(100, "delete");
|
|
}
|
|
if(%zombie.chargecount <= 9){
|
|
%zombie.Fire = schedule(100, %zombie, "ChargeEmitter", %zombie);
|
|
%zombie.chargecount++;
|
|
}
|
|
else
|
|
%zombie.chargecount = 0;
|
|
}
|
|
|
|
function ZFire(%zombie, %target){
|
|
if(isobject(%zombie) && isobject(%target)){
|
|
if(%Zombie.firstFired == 1){
|
|
%vec = vectorsub(%target.getworldboxcenter(),%zombie.getMuzzlePoint(6));
|
|
%vec = vectoradd(%vec, vectorscale(%target.getvelocity(),vectorlen(%vec)/100));
|
|
%zombie.firstFired = 0;
|
|
%zombie.nomove = 0;
|
|
%p = new TracerProjectile()
|
|
{
|
|
dataBlock = LZombieAcidBall;
|
|
initialDirection = %vec;
|
|
initialPosition = %zombie.getMuzzlePoint(6);
|
|
sourceObject = %zombie;
|
|
sourceSlot = 6;
|
|
};
|
|
}
|
|
else{
|
|
%vec = vectorsub(%target.getworldboxcenter(),%zombie.getMuzzlePoint(5));
|
|
%vec = vectoradd(%vec, vectorscale(%target.getvelocity(),vectorlen(%vec)/100));
|
|
%p = new TracerProjectile()
|
|
{
|
|
dataBlock = LZombieAcidBall;
|
|
initialDirection = %vec;
|
|
initialPosition = %zombie.getMuzzlePoint(5);
|
|
sourceObject = %zombie;
|
|
sourceSlot = 5;
|
|
};
|
|
%zombie.firstFired = 1;
|
|
%zombie.Fire = schedule(250, %zombie, "ZFire", %zombie, %target);
|
|
}
|
|
}
|
|
else{
|
|
%zombie.firstFired = 0;
|
|
%zombie.nomove = 0;
|
|
}
|
|
}
|
|
|
|
function Llifttarget(%zombie,%closestclient,%count){
|
|
if(%count == 0)
|
|
%zombie.canmove = 0;
|
|
if(%closestclient.getState() $= "dead" || %Zombie.getState() $= "dead"){
|
|
%zombie.canmove = 1;
|
|
return;
|
|
}
|
|
%target = %closestclient;
|
|
if(!isobject(%target)){
|
|
%zombie.canmove = 1;
|
|
return;
|
|
}
|
|
%pos = %zombie.getworldboxcenter();
|
|
%Tpos = %target.getworldboxcenter();
|
|
%ZtoT = vectorsub(%tpos,%pos);
|
|
if (%count <= 12){
|
|
%newpos = vectoradd(%ZtoT,vectoradd(%pos,"0 0 -0.6"));
|
|
%target.setTransform(%newpos);
|
|
%target.setvelocity("0 0 0");
|
|
}
|
|
else {
|
|
%killtype = getrandom(1,2);
|
|
if(%killtype == 1){
|
|
%closestwall = 20;
|
|
%nv2 = (getword(%ZtoT, 0) * -1);
|
|
%nv1 = getword(%ZtoT, 1);
|
|
%vector1 = vectorscale(vectornormalize(%nv1@" "@%nv2@" 0"),20);
|
|
%nvector1 = vectoradd(%tpos,%vector1);
|
|
%nv2 = getword(%ZtoT, 0);
|
|
%nv1 = (getword(%ZtoT, 1) * -1);
|
|
%vector2 = vectorscale(vectornormalize(%nv1@" "@%nv2@" 0"),20);
|
|
%nvector2 = vectoradd(%tpos,%vector2);
|
|
%searchresultR = containerRayCast(%tpos, %nvector1, $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::VehicleObjectType);
|
|
%searchresultL = containerRayCast(%tpos, %nvector2, $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::VehicleObjectType);
|
|
if(%searchresultR){
|
|
%Hpos = getword(%searchresultR,1)@" "@getword(%searchresultR,2)@" "@getword(%searchresultR,3);
|
|
%distance = vectordist(%Tpos, %Hpos);
|
|
if(%distance <= %closestwall){
|
|
%closestwall = %distance;
|
|
%vector = vectoradd(vectorscale(%vector1,1500),"0 0 100");
|
|
}
|
|
}
|
|
if(%searchresultL){
|
|
%Hpos = getword(%searchresultL,1)@" "@getword(%searchresultL,2)@" "@getword(%searchresultL,3);
|
|
%distance = vectordist(%Tpos, %Hpos);
|
|
if(%distance <= %closestwall){
|
|
%closestwall = %distance;
|
|
%vector = vectoradd(vectorscale(%vector2,1500),"0 0 100");
|
|
}
|
|
}
|
|
if(%closestwall == 20){
|
|
%x = getword(%ZtoT, 0);
|
|
%y = getword(%ZtoT, 1);
|
|
%outvec = vectorscale(vectornormalize(%x@" "@%y@" 0"),50);
|
|
%vector = vectoradd("0 0 -15000",%outvec);
|
|
}
|
|
%target.applyimpulse(%target.getposition(),%vector);
|
|
}
|
|
else if(%killtype == 2){
|
|
%target.infected = 1;
|
|
%target.damage(0, %target.getposition(), 10.0, $DamageType::ZombieL);
|
|
}
|
|
%count = 0;
|
|
%zombie.canmove = 1;
|
|
return;
|
|
}
|
|
%count++;
|
|
%zombie.killingplayer = schedule(150, %zombie, "Llifttarget", %zombie, %closestclient, %count);
|
|
}
|
|
|
|
|
|
function DZombieFire(%zombie,%closestclient){
|
|
%pos = %zombie.getMuzzlePoint(4);
|
|
%tpos = %closestclient.getWorldBoxCenter();
|
|
%tvel = %closestclient.getvelocity();
|
|
%vec = vectorsub(%tpos,%pos);
|
|
%dist = vectorlen(%vec);
|
|
%velpredict = vectorscale(%tvel,(%dist / 50));
|
|
%vector = vectoradd(%vec,%velpredict);
|
|
%ndist = vectorlen(%vector);
|
|
%upvec = "0 0 "@((%ndist / 50) * (%ndist / 50) * 2);
|
|
%vector = vectornormalize(vectoradd(%vector,%upvec));
|
|
%p = new GrenadeProjectile()
|
|
{
|
|
dataBlock = DemonFireball;
|
|
initialDirection = %vector;
|
|
initialPosition = %pos;
|
|
sourceObject = %zombie;
|
|
sourceSlot = 4;
|
|
};
|
|
}
|
|
|
|
function RkillLoop(%zombie,%target,%count){
|
|
if(!isObject(%zombie)){
|
|
%zombie.iscarrying = 0;
|
|
%target.grabbed = 0;
|
|
return;
|
|
}
|
|
if(!isObject(%target)){
|
|
%zombie.iscarrying = 0;
|
|
%target.grabbed = 0;
|
|
return;
|
|
}
|
|
if (%Zombie.getState() $= "dead"){
|
|
%zombie.iscarrying = 0;
|
|
%target.grabbed = 0;
|
|
return;
|
|
}
|
|
if (%target.getState() $= "dead"){
|
|
%zombie.iscarrying = 0;
|
|
%target.grabbed = 0;
|
|
return;
|
|
}
|
|
if(%count == 50){
|
|
%chance = getRandom(1,3);
|
|
if(%chance == 3)
|
|
%target.damage(0, %tpos, 10.0, $DamageType::Zombie);
|
|
else{
|
|
%target.isFTD = 1;
|
|
if(%target.getMountedImage($Backpackslot) !$= "")
|
|
%target.throwPack();
|
|
%target.finishingfall = schedule(5000, 0, "stopFTD", %target);
|
|
}
|
|
%zombie.iscarrying = 0;
|
|
return;
|
|
}
|
|
%target.setPosition(vectoradd(%zombie.getPosition(),"0 0 -4"));
|
|
%target.setVelocity(%zombie.getVelocity());
|
|
%count++;
|
|
%zombie.killingplayer = schedule(100, 0, "RkillLoop", %zombie, %target, %count);
|
|
}
|
|
|
|
function stopFTD(%target){
|
|
%target.isFTD = 0;
|
|
%target.grabbed = 0;
|
|
}
|
|
|
|
function ZSetRandomMove(%zombie){
|
|
if (!isobject(%zombie))
|
|
return;
|
|
%RX = getrandom(-10, 10);
|
|
%RY = getrandom(-10, 10);
|
|
%RZ = getrandom();
|
|
%vector = %RX@" "@%RY@" "@%RZ;
|
|
%zombie.direction = vectornormalize(%vector);
|
|
%zombie.Mnum = getrandom(1, 20);
|
|
%zombie.zombieRmove = schedule(500, %zombie, "ZrandommoveLoop", %zombie);
|
|
}
|
|
|
|
function ZrandommoveLoop(%zombie){
|
|
if (!isobject(%zombie)) {
|
|
return;
|
|
}
|
|
|
|
if (%Zombie.getState() $= "dead") {
|
|
return;
|
|
}
|
|
|
|
if (%zombie.hastarget == 1){
|
|
%zombie.direction = "";
|
|
return;
|
|
}
|
|
if (%zombie.Mnum >= 1){
|
|
%X = getword(%zombie.direction, 1);
|
|
%Y = (getword(%zombie.direction, 0) * -1);
|
|
%none = 0;
|
|
%vector = %X@" "@%Y@" "@%none;
|
|
%zombie.setRotation(fullrot("0 0 0",%vector));
|
|
if(%zombie.type == 1)
|
|
%speed = ($zombie::forwardspeed);
|
|
else if(%zombie.type == 2)
|
|
%speed = ($zombie::Fforwardspeed * 0.6);
|
|
else if(%zombie.type == 4)
|
|
%speed = ($zombie::Dforwardspeed * 0.75);
|
|
else if(%zombie.type == 3)
|
|
%speed = ($zombie::Lforwardspeed * 0.8);
|
|
%vector = vectorscale(%zombie.direction, %speed);
|
|
%zombie.applyimpulse(%zombie.getposition(), %vector);
|
|
%zombie.Mnum = (%zombie.Mnum - 1);
|
|
%zombie.zombieRmove = schedule(500, %zombie, "ZrandommoveLoop", %zombie);
|
|
}
|
|
else if(%zombie.Mnum == 0)
|
|
%zombie.zombieRmove = schedule(100, %zombie, "ZSetRandomMove", %zombie);
|
|
}
|
|
|
|
function InfectLoop(%obj){
|
|
if(%obj.isSentinel)
|
|
return;
|
|
|
|
if((%obj.armor $= "Pure") || (%obj.armor $= "Light")) {
|
|
return;
|
|
}
|
|
|
|
if ($Host::NoInfection)
|
|
{
|
|
%obj.Infected = 0;
|
|
cancel(%obj.infectedDamage);
|
|
|
|
%obj.infectedDamage = "";
|
|
%obj.beats = 0;
|
|
%obj.canZKill = 0;
|
|
|
|
cancel(%player.zombieAttackImpulse);
|
|
return;
|
|
}
|
|
|
|
if (%obj.getState() $= "dead")
|
|
return;
|
|
if(isObject(%obj)){
|
|
if(%obj.beats $= "")
|
|
zombieAttackImpulse(%obj,0);
|
|
if(%obj.beats < 15)
|
|
%obj.setWhiteOut(%obj.beats * 0.05);
|
|
else
|
|
%obj.setDamageFlash(1);
|
|
if(%obj.beats == 15){
|
|
%obj.canZkill = 1;
|
|
}
|
|
if(%obj.beats >=15)
|
|
serverPlay3d("ZombieMoan",%obj.getWorldBoxCenter());
|
|
else if (%obj.beats >= 10)
|
|
playDeathCry(%obj);
|
|
else
|
|
playPain(%obj);
|
|
if(%obj.beats == 20){
|
|
if($host::canZombie $= "")
|
|
$host::canZombie = 0;
|
|
if($host::canZombie == 1)
|
|
makePersonZombie(%obj.getTransform(), %obj.client, ZombieGetRandom());
|
|
else
|
|
%obj.damage(0, %obj.getposition(), 10.0, $DamageType::Zombie);
|
|
return;
|
|
}
|
|
%obj.beats++;
|
|
%obj.infectedDamage = schedule(2000, %obj, "InfectLoop", %obj);
|
|
}
|
|
}
|
|
|
|
function ZkillUpdateScore(%game, %client,%implement){
|
|
if( %implement.getClassName() $= "Turret")
|
|
%client = %implement.getControllingClient();
|
|
else if(%implement.getDataBlock().catagory $= "Vehicles")
|
|
%client = %implement.getControllingClient();
|
|
%client.Zkills++;
|
|
%game.recalcScore(%client);
|
|
}
|
|
|
|
function zombieSpawnLoop(%pos, %radius, %freq){
|
|
if(ZombieGroup.getCount() >= $Host::MaxZombies && $Host::MaxZombies != -1)
|
|
return;
|
|
|
|
if(%freq > 10)
|
|
%freq = 10;
|
|
if(%freq < 1)
|
|
%freq = 1;
|
|
%chance = getRandom(1,50);
|
|
if(%chance <= %freq && $numspawnedzombies < (%freq * 5)){
|
|
%spawnPos = vectorAdd(%pos,(getRandom(0,%radius) - (%radius / 2))@" "@(getRandom(0,%radius) - (%radius / 2))@" getRandom(0,15)");
|
|
%search = containerRayCast(%spawnPos, vectorAdd(%spawnPos,"0 0 -1000"), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType);
|
|
if(%search)
|
|
%spawnPos = getWord(%search,1)@" "@getWord(%search,2)@" "@getWord(%search,3);
|
|
%chance = getRandom(1,65);
|
|
if(%chance <= 25){
|
|
%Zombie = new player(){
|
|
Datablock = "ZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Zombie");
|
|
%Ztype = 1;
|
|
}
|
|
else if(%chance <= 35){
|
|
%Zombie = new player(){
|
|
Datablock = "FZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Ravenger Zombie");
|
|
%Ztype = 2;
|
|
}
|
|
else if(%chance <= 40){
|
|
%Zombie = new player(){
|
|
Datablock = "LordZombieArmor";
|
|
};
|
|
applyskin(%zombie,'ZLord',"Zombie Lord");
|
|
%Zombie.mountImage(ZHead, 3);
|
|
%Zombie.mountImage(ZBack, 4);
|
|
%Zombie.mountImage(ZDummyslotImg, 5);
|
|
%Zombie.mountImage(ZDummyslotImg2, 6);
|
|
%zombie.firstFired = 0;
|
|
%zombie.canmove = 1;
|
|
%Ztype = 3;
|
|
}
|
|
else if(%chance <= 55){
|
|
%Zombie = new player(){
|
|
Datablock = "DemonZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Demon Zombie");
|
|
%zombie.mountImage(ZdummyslotImg, 4);
|
|
%Ztype = 4;
|
|
}
|
|
else if(%chance <= 65){
|
|
%Zombie = new player(){
|
|
Datablock = "RapierZombieArmor";
|
|
};
|
|
applyskin(%zombie,'Zombie',"Rapier Zombie");
|
|
%Zombie.mountImage(ZWingImage, 3);
|
|
%Zombie.mountImage(ZWingImage2, 4);
|
|
%zombie.setActionThread("scoutRoot",true);
|
|
%Ztype = 5;
|
|
}
|
|
%zombie.type = %Ztype;
|
|
%Zombie.setTransform(%spawnPos);
|
|
%Zombie.team = 0;
|
|
%zombie.canjump = 1;
|
|
%zombie.hastarget = 1;
|
|
%zombie.randspawnerstarted = 1;
|
|
AddToZombieGroup(%Zombie);
|
|
schedule(1000, %zombie, "ZombieLookforTarget", %zombie);
|
|
$numspawnedzombies++;
|
|
}
|
|
$zombieloop = schedule(500, 0, "zombieSpawnLoop", %pos, %radius, %freq);
|
|
}
|
|
|
|
function StopZombieSpawnLoop(){
|
|
cancel($zombieloop);
|
|
}
|
|
|
|
function ZombieBloodLust(%obj, %count){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if (%obj.getState() $= "dead")
|
|
return;
|
|
%obj.setDamageFlash(0.5);
|
|
if(%count == 10){
|
|
serverPlay3d("ZombieMoan",%obj.getWorldBoxCenter());
|
|
%count = 0;
|
|
}
|
|
%count++;
|
|
schedule(200, %obj, "ZombieBloodLust", %obj, %count);
|
|
}
|
|
|
|
function makePersonZombie(%trans, %client, %special)
|
|
{
|
|
%client.player.delete();
|
|
|
|
%client.setWeaponsHudClearAll();
|
|
if(%special == 1)
|
|
%data = "ControlLordZombieArmor";
|
|
else if(%special == 2)
|
|
%data = "ControlRapierZombieArmor";
|
|
else if(%special == 3)
|
|
%data = "ControlDemonZombieArmor";
|
|
else
|
|
%data = "ZombieArmor";
|
|
|
|
%player = new Player() {
|
|
dataBlock = %data;
|
|
};
|
|
|
|
if(%special == 1)
|
|
{
|
|
// %player.mountImage(ZHead, 3);
|
|
%player.mountImage(ZBack, 4);
|
|
%player.mountImage(ZDummyslotImg, 5);
|
|
%player.mountImage(ZDummyslotImg2, 6);
|
|
}
|
|
else if(%special == 2)
|
|
{
|
|
%player.mountImage(ZWingImage, 3);
|
|
%player.mountImage(ZWingImage2, 4);
|
|
}
|
|
|
|
%player.setTransform( %trans );
|
|
AddToZombieGroup(%player);
|
|
|
|
// setup some info
|
|
%player.setOwnerClient(%client);
|
|
%player.team = 0;
|
|
%client.outOfBounds = false;
|
|
%player.setEnergyLevel(0);
|
|
%client.player = %player;
|
|
|
|
// updates client's target info for this player
|
|
%player.setTarget(%client.target);
|
|
setTargetDataBlock(%client.target, %player.getDatablock());
|
|
setTargetSensorData(%client.target, PlayerSensor);
|
|
setTargetSensorGroup(%client.target, 1);
|
|
%client.setSensorGroup(1);
|
|
|
|
%client.setControlObject(%player);
|
|
%player.client.clearBackpackIcon();
|
|
|
|
%player.iszombie = 1;
|
|
|
|
if(%special == 1)
|
|
{
|
|
%player.setInventory(LordAcidGun, 1, true);
|
|
%player.use("LordAcidGun"); // Eolk - attempt to fix this problem.
|
|
}
|
|
else if(%special == 2)
|
|
RapierCarryCheck(%player);
|
|
else if(%special == 3)
|
|
{
|
|
%player.setInventory(DZShot, 1, true);
|
|
%player.use("DZShot"); // Eolk - attempt to fix this problem.
|
|
}
|
|
|
|
ZombieBloodLust(%player,0);
|
|
if(!%special)
|
|
zombieAttackImpulse(%player,80);
|
|
}
|
|
|
|
// This keeps the rapier-human squatting and acting like a real rapier when carrying someone to die.
|
|
function RapierCarryCheck(%obj)
|
|
{
|
|
if(!isObject(%obj) || %obj.getState() $= "Dead")
|
|
return;
|
|
|
|
if(%obj.isCarrying == 1)
|
|
{
|
|
%vector = VectorScale(%obj.getEyeVector(), $Zombie::RForwardSpeed + %obj.getDatablock().mass);
|
|
%vector = getword(%vector, 0) SPC getword(%vector, 1) SPC ($Zombie::rupvec * 1.5);
|
|
%obj.applyImpulse(%obj.position, %vector);
|
|
}
|
|
|
|
%obj.setActionThread("scoutroot", 1);
|
|
%obj.RImpulse = schedule(500, 0, "RapierCarryCheck", %obj);
|
|
}
|
|
|
|
function zombieAttackImpulse(%obj, %count){
|
|
if(!isObject(%obj)) {
|
|
return;
|
|
}
|
|
|
|
if (%obj.getState() $= "Dead") {
|
|
return;
|
|
}
|
|
|
|
%pos = %obj.getposition();
|
|
InitContainerRadiusSearch(%pos, %count, $TypeMasks::PlayerObjectType || $TypeMasks::VehicleObjectType);
|
|
while ((%objtarget = containerSearchNext()) != 0){
|
|
if(isObject(%objtarget) && %objtarget !$= %obj){
|
|
%objarmortype = %objtarget.getdatablock().getname();
|
|
if(%objarmortype $= "ZombieArmor" || %objarmortype $= "FZombieArmor" || %objarmortype $= "LordZombieArmor" || %objarmortype $= "DemonZombieArmor" || %objarmortype $= "ControlDemonZombieArmor" || %objarmortype $= "RapierZombieArmor" || %objarmortype $= "ControlRapierZombieArmor" || %objarmortype $= "ControlLordZombieArmor")
|
|
%objiszomb = 1;
|
|
if(!(%objiszomb) && %objtarget.iszombie != 1) {
|
|
%vec = vectorNormalize(vectorSub(%objtarget.getWorldBoxCenter(),%obj.getWorldBoxCenter()));
|
|
if(vectorDist(%vec,%obj.getForwardVector()) <= 0.5){
|
|
if(%count <= 200){
|
|
%impulse = (%count / 20) * 90;
|
|
%up = (%count / 100) * 90;
|
|
}
|
|
else{
|
|
%impulse = 900;
|
|
%up = 180;
|
|
}
|
|
%vec = vectorScale(%vec,%impulse);
|
|
%vec = vectorAdd(%vec,"0 0 "@%up);
|
|
%obj.applyimpulse(%obj.getPosition(),%vec);
|
|
%count++;
|
|
%obj.zombieAttackImpulse = schedule(500, 0, "zombieAttackImpulse", %obj, %count);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
%objiszomb = 0;
|
|
}
|
|
%count++;
|
|
%obj.zombieAttackImpulse = schedule(500, 0, "zombieAttackImpulse", %obj, %count);
|
|
}
|
|
|
|
function AddToZombieGroup(%player)
|
|
{
|
|
if(isObject(%player))
|
|
{
|
|
%group = nameToID("MissionCleanup/ZombieGroup");
|
|
if(!isObject(%group))
|
|
{
|
|
%group = new SimGroup("ZombieGroup");
|
|
MissionCleanup.add(%group);
|
|
}
|
|
|
|
%group.add(%player);
|
|
}
|
|
}
|
|
|
|
function RemoveFromZombieGroup(%player)
|
|
{
|
|
if(isObject(%player))
|
|
{
|
|
%group = nameToID("MissionCleanup/ZombieGroup");
|
|
if(!isObject(%group))
|
|
{
|
|
%group = new SimGroup("ZombieGroup");
|
|
MissionCleanup.add(%group);
|
|
}
|
|
|
|
%group.remove(%player);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
//------------------------DEMON MOTHER STUFF---------------------------
|
|
//---------------------------------------------------------------------
|
|
|
|
datablock SeekerProjectileData(DMMissile)
|
|
{
|
|
casingShapeName = "weapon_missile_casement.dts";
|
|
projectileShapeName = "weapon_missile_projectile.dts";
|
|
hasDamageRadius = true;
|
|
indirectDamage = 0.5;
|
|
damageRadius = 5.0;
|
|
radiusDamageType = $DamageType::Zombie;
|
|
kickBackStrength = 2000;
|
|
|
|
explosion = "MissileExplosion";
|
|
splash = MissileSplash;
|
|
velInheritFactor = 1.0; // to compensate for slow starting velocity, this value
|
|
// is cranked up to full so the missile doesn't start
|
|
// out behind the player when the player is moving
|
|
// very quickly - bramage
|
|
|
|
baseEmitter = MortarSmokeEmitter;
|
|
delayEmitter = MissileFireEmitter;
|
|
puffEmitter = MissilePuffEmitter;
|
|
bubbleEmitter = GrenadeBubbleEmitter;
|
|
bubbleEmitTime = 1.0;
|
|
|
|
exhaustEmitter = MissileLauncherExhaustEmitter;
|
|
exhaustTimeMs = 300;
|
|
exhaustNodeName = "muzzlePoint1";
|
|
|
|
lifetimeMS = 10000; // z0dd - ZOD, 4/14/02. Was 6000
|
|
muzzleVelocity = 10.0;
|
|
maxVelocity = 35.0; // z0dd - ZOD, 4/14/02. Was 80.0
|
|
turningSpeed = 23.0;
|
|
acceleration = 15.0;
|
|
|
|
proximityRadius = 2.5;
|
|
|
|
terrainAvoidanceSpeed = 10;
|
|
terrainScanAhead = 7;
|
|
terrainHeightFail = 1;
|
|
terrainAvoidanceRadius = 3;
|
|
|
|
flareDistance = 40;
|
|
flareAngle = 20;
|
|
minSeekHeat = 0.0;
|
|
|
|
sound = MissileProjectileSound;
|
|
|
|
hasLight = true;
|
|
lightRadius = 5.0;
|
|
lightColor = "0.2 0.05 0";
|
|
|
|
useFlechette = true;
|
|
flechetteDelayMs = 250;
|
|
casingDeb = FlechetteDebris;
|
|
|
|
explodeOnWaterImpact = false;
|
|
};
|
|
|
|
datablock LinearFlareProjectileData(DMPlasma)
|
|
{
|
|
doDynamicClientHits = true;
|
|
|
|
directDamage = 0;
|
|
directDamageType = $DamageType::Zombie;
|
|
hasDamageRadius = true;
|
|
indirectDamage = 0.8; // z0dd - ZOD, 4/25/02. Was 0.5
|
|
damageRadius = 15.0;
|
|
kickBackStrength = 1500;
|
|
radiusDamageType = $DamageType::Zombie;
|
|
explosion = MortarExplosion;
|
|
splash = PlasmaSplash;
|
|
|
|
dryVelocity = 85.0; // z0dd - ZOD, 4/25/02. Was 50. Velocity of projectile out of water
|
|
wetVelocity = -1;
|
|
velInheritFactor = 1.0;
|
|
fizzleTimeMS = 4000;
|
|
lifetimeMS = 2500; // z0dd - ZOD, 4/25/02. Was 6000
|
|
explodeOnDeath = true;
|
|
reflectOnWaterImpactAngle = 0.0;
|
|
explodeOnWaterImpact = true;
|
|
deflectionOnWaterImpact = 0.0;
|
|
fizzleUnderwaterMS = -1;
|
|
|
|
activateDelayMS = 100;
|
|
|
|
scale = "3.0 3.0 3.0";
|
|
numFlares = 30;
|
|
flareColor = "0.1 0.3 1.0";
|
|
flareModTexture = "flaremod";
|
|
flareBaseTexture = "flarebase";
|
|
};
|
|
|
|
function DemonMotherCreate(%pos){
|
|
if(ZombieGroup.getCount() >= $Host::MaxZombies && $Host::MaxZombies != -1)
|
|
{
|
|
error("Too many zombies. Cannot create demon mother");
|
|
return;
|
|
}
|
|
|
|
%obj = new player(){
|
|
Datablock = "DemonMotherZombieArmor";
|
|
};
|
|
%obj.setTransform(%pos);
|
|
%obj.team = 0;
|
|
MissionCleanup.add(%obj);
|
|
AddToZombieGroup(%obj);
|
|
schedule(1000, 0, "DemonMotherInitiate", %obj);
|
|
|
|
// Eolk - Needs to return %obj now
|
|
return %obj;
|
|
}
|
|
|
|
function DemonMotherInitiate(%obj){
|
|
if(!isObject(%obj))
|
|
return;
|
|
DemonMotherDefense(%obj);
|
|
DemonMotherThink(%obj);
|
|
%obj.mountImage(ZdummyslotImg, 4);
|
|
%obj.justshot = 0;
|
|
%obj.justmelee = 0;
|
|
}
|
|
|
|
function DemonMotherThink(%obj){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
%pos = %obj.getposition();
|
|
%count = ClientGroup.getCount();
|
|
%closestClient = -1;
|
|
%closestDistance = 32767;
|
|
for(%i = 0; %i < %count; %i++)
|
|
{
|
|
%cl = ClientGroup.getObject(%i);
|
|
if(isObject(%cl.player)){
|
|
%testPos = %cl.player.getWorldBoxCenter();
|
|
%distance = vectorDist(%pos, %testPos);
|
|
if (%distance > 0 && %distance < %closestDistance && %cl.player.isFTD != 1 && %cl.player.iszombie != 1)
|
|
{
|
|
%closestClient = %cl;
|
|
%closestDistance = %distance;
|
|
}
|
|
}
|
|
}
|
|
if(%closestClient != -1){
|
|
%searchobject = %closestclient.player;
|
|
%dist = vectorDist(%pos,%searchobject.getPosition());
|
|
if(%dist <= 100){
|
|
if(%dist <= 50){ //ok were now in combat mode, lets decide on what we should do, move attack, or shoot.
|
|
if(%obj.justmelee == 1){ //if we just used a melee attack, maybe we should follow it up with a shot attack.
|
|
if(%dist >= 10){ //good were far enough away, lets shoot em.
|
|
%rand = getrandom(1,3);
|
|
if(%rand <= 2)
|
|
DemonMotherSpermAttack(%obj,%searchobject);
|
|
else
|
|
DemonMotherFireRainAttack(%obj,%searchobject);
|
|
}
|
|
else //damn, to close, ok lung at him
|
|
DemonMotherLungAttack(%obj,%searchobject);
|
|
}
|
|
else{
|
|
%rand = getRandom(1,5); //ok so theres 3 good possible attacks here, so lets get a random variable and decide what to do.
|
|
if(%rand == 1)
|
|
DemonMotherPlasmaAttack(%obj,%searchobject);
|
|
else if(%rand <= 3)
|
|
DemonMotherStrafeAttack(%obj,%searchobject);
|
|
else
|
|
DemonMotherFlyAttack(%obj,%searchobject);
|
|
}
|
|
}
|
|
else{ //ok, were to far away, maybe we should shoot at them.
|
|
if(%obj.justshot == 1) //humm we just attacked, ok, let charge him, get in close
|
|
DemonMotherChargeIn(%obj,%searchobject);
|
|
else{ //were good to fire, FIRE AWAY!
|
|
%rand = getRandom(1,5); //ok so theres 3 good possible attacks here, so lets get a random variable and decide what to do.
|
|
if(%rand == 1)
|
|
DemonMotherFireRainAttack(%obj,%searchobject);
|
|
else if(%rand <= 3)
|
|
DemonMotherMissileAttack(%obj,%searchobject);
|
|
else
|
|
DemonMotherSpermAttack(%obj,%searchobject);
|
|
}
|
|
}
|
|
}
|
|
else if(%dist > 200){
|
|
%rand = getrandom(1,120);
|
|
if(%rand == 94) //please, dont ask why i choose this number, it just poped in my head
|
|
DemonMotherDemonSpawn(%obj);
|
|
else
|
|
DemonMotherMoveToTarget(%obj,%searchobject);
|
|
}
|
|
else
|
|
DemonMotherMoveToTarget(%obj,%searchobject);
|
|
|
|
%obj.justshot = 0;
|
|
%obj.justmelee = 0;
|
|
}
|
|
else{
|
|
schedule(500, 0, "DemonMotherThink", %obj);
|
|
}
|
|
}
|
|
|
|
function DemonMotherDefense(%obj){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
%pos = %obj.getposition();
|
|
InitContainerRadiusSearch(%pos, 250, $TypeMasks::ProjectileObjectType);
|
|
while ((%searchObject = containerSearchNext()) != 0){
|
|
%projpos = %searchobject.getPosition();
|
|
%dist = vectorDist(%pos,%projpos);
|
|
if(%dist <= 100){
|
|
if(%searchobject.lastpos)
|
|
%searchobject.delete();
|
|
}
|
|
else
|
|
%searchobject.lastpos = %projpos;
|
|
}
|
|
schedule(50, "DemonMotherDefense", %obj);
|
|
}
|
|
|
|
function DemonMotherSpermAttack(%obj,%target){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
if(!isObject(%target)){
|
|
DemonMotherThink(%obj);
|
|
return;
|
|
}
|
|
FaceTarget(%obj,%target);
|
|
if(%obj.chargecount $= "")
|
|
%obj.chargecount = 0;
|
|
%charge = new ParticleEmissionDummy()
|
|
{
|
|
position = %obj.getMuzzlePoint(4);
|
|
dataBlock = "defaultEmissionDummy";
|
|
emitter = "FlameEmitter";
|
|
};
|
|
MissionCleanup.add(%charge);
|
|
%charge.schedule(100, "delete");
|
|
|
|
if(%obj.chargecount == 7){
|
|
%vec = vectorsub(%target.getworldboxcenter(),%obj.getMuzzlePoint(4));
|
|
%vec = vectoradd(%vec, vectorscale(%target.getvelocity(),vectorlen(%vec)/100));
|
|
%p = new TracerProjectile()
|
|
{
|
|
dataBlock = LZombieAcidBall;
|
|
initialDirection = %vec;
|
|
initialPosition = %obj.getMuzzlePoint(4);
|
|
sourceObject = %obj;
|
|
sourceSlot = 6;
|
|
};
|
|
}
|
|
if(%obj.chargecount == 9){
|
|
%vec = vectorsub(%target.getworldboxcenter(),%obj.getMuzzlePoint(4));
|
|
%vec = vectoradd(%vec, vectorscale(%target.getvelocity(),vectorlen(%vec)/100));
|
|
%p = new TracerProjectile()
|
|
{
|
|
dataBlock = LZombieAcidBall;
|
|
initialDirection = %vec;
|
|
initialPosition = %obj.getMuzzlePoint(4);
|
|
sourceObject = %obj;
|
|
sourceSlot = 6;
|
|
};
|
|
}
|
|
|
|
if(%obj.chargecount <= 9){
|
|
schedule(100, 0, "DemonMotherSpermAttack", %obj, %target);
|
|
%obj.chargecount++;
|
|
}
|
|
else{
|
|
%obj.chargecount = 0;
|
|
%obj.justshot = 1;
|
|
DemonMotherThink(%obj);
|
|
}
|
|
}
|
|
|
|
function DemonMotherLungAttack(%obj,%target){
|
|
FaceTarget(%obj,%target);
|
|
%vector = vectorNormalize(vectorSub(%target.getPosition(), %obj.getPosition()));
|
|
%vector = vectorscale(%vector, 4000);
|
|
%x = Getword(%vector,0);
|
|
%y = Getword(%vector,1);
|
|
%z = Getword(%vector,2);
|
|
%vector = %x@" "@%y@" 400";
|
|
%obj.applyImpulse(%obj.getPosition(), %vector);
|
|
|
|
%obj.justmelee = 1;
|
|
schedule(750, 0, "DemonMotherThink", %obj);
|
|
}
|
|
|
|
function DemonMotherStrafeAttack(%obj,%target){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
if(%obj.chargecount $= "")
|
|
%obj.chargecount = 0;
|
|
if(%obj.chargecount <= 8){
|
|
%obj.setVelocity("0 0 0");
|
|
FaceTarget(%obj,%target);
|
|
%vector = vectorNormalize(vectorSub(%target.getPosition(), %obj.getPosition()));
|
|
%vector = vectorscale(%vector, 3250);
|
|
%x = Getword(%vector,0);
|
|
%y = Getword(%vector,1);
|
|
%nv1 = %y;
|
|
%nv2 = (%x * -1);
|
|
%vector = %nv1@" "@%nv2@" 0";
|
|
%obj.applyImpulse(%obj.getPosition(), %vector);
|
|
}
|
|
else if(%obj.chargecount <= 11){
|
|
%obj.setvelocity("0 0 0");
|
|
FaceTarget(%obj,%target);
|
|
%vector = vectorNormalize(vectorSub(%target.getPosition(), %obj.getPosition()));
|
|
%vector = vectorscale(%vector, 4500);
|
|
%x = Getword(%vector,0);
|
|
%y = Getword(%vector,1);
|
|
%z = Getword(%vector,2);
|
|
%vector = %x@" "@%y@" 150";
|
|
%obj.applyImpulse(%obj.getPosition(), %vector);
|
|
}
|
|
else{
|
|
%obj.chargecount = 0;
|
|
%obj.justmelee = 1;
|
|
schedule(250, 0, "DemonMotherThink", %obj);
|
|
return;
|
|
}
|
|
schedule(250, 0, "DemonMotherStrafeAttack", %obj, %target);
|
|
%obj.chargecount++;
|
|
}
|
|
|
|
function DemonMotherFlyAttack(%obj,%target){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
if(%obj.chargecount $= "")
|
|
%obj.chargecount = 0;
|
|
if(%obj.chargecount <= 9){
|
|
FaceTarget(%obj,%target);
|
|
%obj.setvelocity("0 0 10");
|
|
%obj.chargecount++;
|
|
schedule(100, 0, "DemonMotherFlyAttack",%obj,%target);
|
|
}
|
|
else if(%obj.chargecount == 10){
|
|
FaceTarget(%obj,%target);
|
|
%obj.setvelocity("0 0 5");
|
|
%vector = vectorSub(%target.getPosition(),%obj.getPosition());
|
|
%nVec = vectorNormalize(%vector);
|
|
%vector = vectorAdd(%vector,vectorscale(%nvec,-4));
|
|
%obj.attackpos = vectorAdd(%obj.getPosition(),%vector);
|
|
%obj.attackdir = %nVec;
|
|
// echo(%obj.getPosition() SPC %target.getPosition() SPC %obj.attackpos SPC %obj.attackdir);
|
|
%obj.startFade(400, 0, true);
|
|
%obj.chargecount++;
|
|
schedule(400, 0, "DemonMotherFlyAttack",%obj,%target);
|
|
}
|
|
else if(%obj.chargecount >= 11){
|
|
%obj.startFade(500, 0, false);
|
|
%obj.setPosition(%obj.attackpos);
|
|
%obj.setvelocity(vectorscale(%obj.attackdir,25));
|
|
%obj.justmelee = 1;
|
|
%obj.chargecount = 0;
|
|
// echo(%obj.getPosition() SPC %target.getPosition() SPC %obj.attackpos SPC %obj.attackdir);
|
|
%obj.attackpos = "";
|
|
%obj.attackdir = "";
|
|
schedule(1000, 0, "DemonMotherThink",%obj);
|
|
}
|
|
}
|
|
|
|
function DemonMotherFireRainAttack(%obj,%target){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
if(%obj.chargecount $= "")
|
|
%obj.chargecount = 0;
|
|
if(%obj.chargecount == 0){
|
|
FaceTarget(%obj, %target);
|
|
for(%i = 0; %i < 10; %i++){
|
|
%pos = %obj.getPosition();
|
|
%x = getRandom(0,10) - 5;
|
|
%y = getRandom(0,10) - 5;
|
|
%vec = vectorAdd(%pos,%x SPC %y SPC "5");
|
|
%searchResult = containerRayCast(%vec, vectorAdd(%vec,"0 0 -10"), $TypeMasks::TerrainObjectType, %obj);
|
|
|
|
%charge = new ParticleEmissionDummy()
|
|
{
|
|
position = posFromRaycast(%searchresult);
|
|
dataBlock = "defaultEmissionDummy";
|
|
emitter = "FlameEmitter";
|
|
};
|
|
MissionCleanup.add(%charge);
|
|
%charge.schedule(1500, "delete");
|
|
}
|
|
%obj.chargecount++;
|
|
schedule(1000, 0, "DemonMotherFireRainAttack",%obj,%target);
|
|
}
|
|
else{
|
|
%x = (getRandom() * 2) - 1;
|
|
%y = (getRandom() * 2) - 1;
|
|
%z = getRandom();
|
|
%vec = vectorNormalize(%x SPC %y SPC %z);
|
|
%pos = vectorAdd(%target.getPosition(),vectorScale(%vec, 20));
|
|
for(%i = 0;%i < 10;%i++){
|
|
%x = getRandom(0,14) - 7;
|
|
%y = getRandom(0,14) - 7;
|
|
%spwpos = vectorAdd(%pos,%x SPC %y SPC "2");
|
|
%p = new GrenadeProjectile()
|
|
{
|
|
dataBlock = DemonFireball;
|
|
initialDirection = vectorScale(%vec,-1);
|
|
initialPosition = %spwpos;
|
|
sourceObject = %obj;
|
|
sourceSlot = 4;
|
|
};
|
|
}
|
|
%obj.justshot = 1;
|
|
%obj.chargecount = 0;
|
|
schedule(1000, 0, "DemonMotherThink",%obj);
|
|
}
|
|
}
|
|
|
|
function DemonMotherMissileAttack(%obj,%target){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
if(%obj.chargecount $= "")
|
|
%obj.chargecount = 0;
|
|
if(%obj.chargecount == 0){
|
|
%obj.chargecount++;
|
|
schedule(1000, 0, "DemonMotherMissileAttack", %obj, %target);
|
|
}
|
|
else{
|
|
%vec = vectorNormalize(vectorSub(%target.getPosition(),%obj.getPosition()));
|
|
%p = new SeekerProjectile()
|
|
{
|
|
dataBlock = DMMissile;
|
|
initialDirection = %vec;
|
|
initialPosition = %obj.getMuzzlePoint(4);
|
|
sourceObject = %obj;
|
|
sourceSlot = 4;
|
|
};
|
|
%beacon = new BeaconObject() {
|
|
dataBlock = "SubBeacon";
|
|
beaconType = "vehicle";
|
|
position = %target.getWorldBoxCenter();
|
|
};
|
|
%beacon.team = 0;
|
|
%beacon.setTarget(0);
|
|
MissionCleanup.add(%beacon);
|
|
%p.setObjectTarget(%beacon);
|
|
DemonMotherMissileFollow(%target,%beacon,%p);
|
|
|
|
%obj.justshot = 1;
|
|
%obj.chargecount = 0;
|
|
schedule(1000, 0, "DemonMotherThink", %obj);
|
|
}
|
|
}
|
|
|
|
function DemonMotherMissileFollow(%target,%beacon,%missile){
|
|
if(!isObject(%target)){
|
|
%beacon.delete();
|
|
return;
|
|
}
|
|
if(!isObject(%missile)){
|
|
%beacon.delete();
|
|
return;
|
|
}
|
|
%beacon.setPosition(%target.getWorldBoxCenter());
|
|
schedule(100, 0, "DemonMotherMissileFollow", %target, %beacon, %missile);
|
|
}
|
|
|
|
function DemonMotherPlasmaAttack(%obj,%target){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
if(%obj.chargecount $= "")
|
|
%obj.chargecount = 0;
|
|
if(%obj.chargecount <= 9){
|
|
%obj.setVelocity("0 0 10");
|
|
%obj.chargecount++;
|
|
schedule(100, 0, "DemonMotherPlasmaAttack", %obj, %target);
|
|
}
|
|
else{
|
|
%obj.setVelocity("0 0 3");
|
|
%vec = vectorNormalize(vectorSub(%target.getPosition(),%obj.getPosition()));
|
|
%p = new LinearFlareProjectile()
|
|
{
|
|
dataBlock = DMPlasma;
|
|
initialDirection = %vec;
|
|
initialPosition = %obj.getMuzzlePoint(4);
|
|
sourceObject = %obj;
|
|
sourceSlot = 4;
|
|
};
|
|
%obj.chargecount = 0;
|
|
%obj.justshot = 1;
|
|
schedule(1000, 0, "DemonMotherThink", %obj);
|
|
}
|
|
}
|
|
|
|
function DemonMotherChargeIn(%obj,%target){
|
|
if(!isObject(%obj))
|
|
return;
|
|
if(%obj.getState() $= "dead")
|
|
return;
|
|
if(%obj.chargecount $= "")
|
|
%obj.chargecount = 0;
|
|
if(%obj.chargecount <= 4){
|
|
FaceTarget(%obj, %target);
|
|
%vec = vectorNormalize(vectorSub(%target.getPosition(),%obj.getPosition()));
|
|
%obj.setvelocity(vectorScale(%vec,50));
|
|
%obj.chargecount++;
|
|
schedule(500, 0, "DemonMotherChargeIn", %obj, %target);
|
|
}
|
|
else{
|
|
%obj.justmelee = 1;
|
|
%obj.chargecount = 0;
|
|
DemonMotherThink(%obj);
|
|
}
|
|
}
|
|
|
|
function DemonMotherMoveToTarget(%obj,%target){
|
|
FaceTarget(%obj,%target);
|
|
%vector = vectorNormalize(vectorSub(%target.getPosition(), %obj.getPosition()));
|
|
%vector = vectorscale(%vector, 1200);
|
|
%x = Getword(%vector,0);
|
|
%y = Getword(%vector,1);
|
|
%z = Getword(%vector,2);
|
|
%vector = %x@" "@%y@" 150";
|
|
%obj.applyImpulse(%obj.getPosition(), %vector);
|
|
|
|
schedule(500, 0, "DemonMotherThink", %obj);
|
|
}
|
|
|
|
function DemonMotherDemonSpawn(%obj){
|
|
for(%i = 0; %i < 5; %i++){
|
|
%pos = %obj.getPosition();
|
|
%x = getRandom(0,200) - 100;
|
|
%y = getRandom(0,200) - 100;
|
|
%vec = vectorAdd(%pos,%x SPC %y SPC "40");
|
|
%searchResult = containerRayCast(%vec, vectorAdd(%vec,"0 0 -80"), $TypeMasks::TerrainObjectType, %obj);
|
|
|
|
%charge = new ParticleEmissionDummy()
|
|
{
|
|
position = posFromRaycast(%searchresult);
|
|
dataBlock = "defaultEmissionDummy";
|
|
emitter = "FlameEmitter";
|
|
};
|
|
MissionCleanup.add(%charge);
|
|
%charge.schedule(1100, "delete");
|
|
schedule(1000, 0, "startAzombie", posFromRaycast(%searchresult), 4);
|
|
}
|
|
schedule(1500, 0, "DemonMotherThink", %obj);
|
|
}
|
|
|
|
function FaceTarget(%obj,%target){
|
|
%vector = vectorNormalize(vectorSub(%target.getPosition(), %obj.getPosition()));
|
|
%v1 = getword(%vector, 0);
|
|
%v2 = getword(%vector, 1);
|
|
%nv1 = %v2;
|
|
%nv2 = (%v1 * -1);
|
|
%vector2 = %nv1@" "@%nv2@" 0";
|
|
%obj.setRotation(fullrot("0 0 0",%vector2));
|
|
}
|