mirror of
https://github.com/PhantomGamesDevelopment/TWM2.git
synced 2026-01-19 19:44:47 +00:00
Zombie Lord Update
Added in the new code for zombie lords.
This commit is contained in:
parent
1e9d2bf1b5
commit
76f973712a
|
|
@ -78,6 +78,11 @@ PLEASE NOTE: I've moved all old changelogs into the version_history folder. This
|
|||
* Ravager
|
||||
* Ravagers will now perform ambush style attacks on targets, making them much more challenging
|
||||
* Increased the XP reward from killing ravager zombies
|
||||
* Lord
|
||||
* Modified the behavior of zombie lords
|
||||
* Replaced the acid cannon with an anti-tank photon cannon
|
||||
* Zombie lords will now preferential target enemy ground armor before infantry, and engage their photon cannon on targets
|
||||
* Zombie lords can now activate a defensive barrier to protect themselves and allies from damage temporarily... enjoy this new rage inducing mechanic :)
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -39,15 +39,20 @@ $Zombie::SpeedUpdateTime[3] = 500;
|
|||
|
||||
//$Zombie::LungeDistance: How far (m) a zombie must be to lunge at a target
|
||||
$Zombie::LungeDistance = 10;
|
||||
|
||||
// SPECIFIC ZOMBIE TYPE GLOBALS
|
||||
|
||||
//$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;
|
||||
|
||||
//$Zombie::ZombieLordShieldHealth: How much health the zombie lord energy barrier hasCP
|
||||
$Zombie::ZombieLordShieldHealth = 10.0;
|
||||
//$Zombie::ZombieLordShieldEnergy: How much energy the shield starts with. Note: Multiply this value by $Zombie::SpeedUpdateTime[3] to determine how long in MS the shield will be up.
|
||||
$Zombie::ZombieLordShieldEnergy = 50;
|
||||
//$Zombie::ZombieLordWeaponCooldown: How long in MS that the zombie lord's photon cannon must cool down for
|
||||
$Zombie::ZombieLordPhotonCooldown = 15000;
|
||||
|
||||
//$Zombie::RapierUpwardScaling: How fast a rapier zombie will ascend when holding a player
|
||||
$Zombie::RapierUpwardScaling = 750;
|
||||
|
||||
//MISC Globals, Do not edit.
|
||||
$Zombie::killpoints = 5;
|
||||
|
|
@ -197,6 +202,10 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
|
|||
%arg1.recentShift = %arg3;
|
||||
case "canshield":
|
||||
%arg1.canShield = %arg3;
|
||||
case "firingweapon":
|
||||
%arg1.firingWeapon = %arg3;
|
||||
case "canfireweapon":
|
||||
%arg1.canFireWeapon = %arg3;
|
||||
|
||||
//lookForTarget(%zombie, [%pilot], [%groundVeh]): Identify the closest target, and the distance to that target
|
||||
case "lookfortarget":
|
||||
|
|
@ -398,9 +407,9 @@ function TWM2Lib_Zombie_Core(%functionName, %arg1, %arg2, %arg3, %arg4) {
|
|||
%zombie.mountImage(ZBack, 4);
|
||||
%zombie.mountImage(ZDummyslotImg, 5);
|
||||
%zombie.mountImage(ZDummyslotImg2, 6);
|
||||
%zombie.setInventory(AcidCannon, 1, true);
|
||||
%zombie.use(AcidCannon);
|
||||
%zombie.firstFired = 0;
|
||||
%zombie.mountImage(zLordPhotonCannonImg, 7);
|
||||
%zombie.canFireWeapon = 1;
|
||||
%zombie.canShield = 1;
|
||||
%zombie.canmove = 1;
|
||||
|
||||
//Demon Zombie
|
||||
|
|
|
|||
|
|
@ -1,258 +1,517 @@
|
|||
datablock AudioProfile(ZLordFootSound)
|
||||
{
|
||||
filename = "fx/weapons/grenade_explode_UW.wav";
|
||||
description = AudioBomb3d;
|
||||
preload = true;
|
||||
datablock AudioProfile(ZLordFootSound) {
|
||||
filename = "fx/weapons/grenade_explode_UW.wav";
|
||||
description = AudioBomb3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock AudioProfile(HZLordFootSound)
|
||||
{
|
||||
filename = "fx/weapons/SpinFusor_explode_UW.wav";
|
||||
description = AudioBomb3d;
|
||||
preload = true;
|
||||
datablock AudioProfile(HZLordFootSound) {
|
||||
filename = "fx/weapons/SpinFusor_explode_UW.wav";
|
||||
description = AudioBomb3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock PlayerData(LordZombieArmor) : HeavyMaleBiodermArmor
|
||||
{
|
||||
shapefile = "TR2medium_male.dts";
|
||||
mass = 500;
|
||||
maxDamage = 18.0;
|
||||
minImpactSpeed = 50;
|
||||
speedDamageScale = 0.015;
|
||||
boundingBox = "2.9 2.9 4.8";
|
||||
datablock PlayerData(LordZombieArmor) : HeavyMaleBiodermArmor {
|
||||
shapefile = "TR2medium_male.dts";
|
||||
mass = 500;
|
||||
maxDamage = 18.0;
|
||||
minImpactSpeed = 50;
|
||||
speedDamageScale = 0.015;
|
||||
boundingBox = "2.9 2.9 4.8";
|
||||
|
||||
underwaterJetForce = 10;
|
||||
underwaterJetForce = 10;
|
||||
|
||||
LFootSoftSound = ZLordFootSound;
|
||||
RFootSoftSound = ZLordFootSound;
|
||||
LFootHardSound = HZLordFootSound;
|
||||
RFootHardSound = HZLordFootSound;
|
||||
LFootMetalSound = ZLordFootSound;
|
||||
RFootMetalSound = ZLordFootSound;
|
||||
LFootSnowSound = ZLordFootSound;
|
||||
RFootSnowSound = ZLordFootSound;
|
||||
LFootSoftSound = ZLordFootSound;
|
||||
RFootSoftSound = ZLordFootSound;
|
||||
LFootHardSound = HZLordFootSound;
|
||||
RFootHardSound = HZLordFootSound;
|
||||
LFootMetalSound = ZLordFootSound;
|
||||
RFootMetalSound = ZLordFootSound;
|
||||
LFootSnowSound = ZLordFootSound;
|
||||
RFootSnowSound = ZLordFootSound;
|
||||
|
||||
damageScale[$DamageType::M1700] = 1.5;
|
||||
damageScale[$DamageType::M1700] = 1.5;
|
||||
|
||||
max[RepairKit] = 0;
|
||||
max[Mine] = 0;
|
||||
max[Grenade] = 0;
|
||||
};
|
||||
|
||||
datablock ShapeBaseImageData(ZHead)
|
||||
{
|
||||
shapeFile = "bioderm_heavy.dts";
|
||||
emap = false;
|
||||
mountPoint = 1;
|
||||
offset = "0 0.25 -1.5";
|
||||
rotation = "1 0 0 15";
|
||||
datablock ShapeBaseImageData(ZHead) {
|
||||
shapeFile = "bioderm_heavy.dts";
|
||||
emap = false;
|
||||
mountPoint = 1;
|
||||
offset = "0 0.25 -1.5";
|
||||
rotation = "1 0 0 15";
|
||||
};
|
||||
|
||||
datablock ShapeBaseImageData(ZBack)
|
||||
{
|
||||
shapeFile = "bioderm_medium.dts";
|
||||
emap = false;
|
||||
mountPoint = 1;
|
||||
offset = "0 0.25 -1.25";
|
||||
rotation = "-1 0 0 10";
|
||||
datablock ShapeBaseImageData(ZBack) {
|
||||
shapeFile = "bioderm_medium.dts";
|
||||
emap = false;
|
||||
mountPoint = 1;
|
||||
offset = "0 0.25 -1.25";
|
||||
rotation = "-1 0 0 10";
|
||||
};
|
||||
|
||||
datablock ShapeBaseImageData(ZDummyslotImg)
|
||||
{
|
||||
shapeFile = "turret_muzzlepoint.dts";
|
||||
emap = false;
|
||||
datablock ShapeBaseImageData(ZDummyslotImg) {
|
||||
shapeFile = "turret_muzzlepoint.dts";
|
||||
emap = false;
|
||||
};
|
||||
|
||||
datablock ShapeBaseImageData(ZDummyslotImg2)
|
||||
{
|
||||
shapeFile = "turret_muzzlepoint.dts";
|
||||
emap = false;
|
||||
offset = "-1.5 0 0";
|
||||
datablock ShapeBaseImageData(ZDummyslotImg2) {
|
||||
shapeFile = "turret_muzzlepoint.dts";
|
||||
emap = false;
|
||||
offset = "-1.5 0 0";
|
||||
};
|
||||
|
||||
function LZombiemovetotarget(%zombie){
|
||||
if(!isobject(%Zombie))
|
||||
return;
|
||||
if(%Zombie.getState() $= "dead") {
|
||||
%zombie.throwweapon(1);
|
||||
return;
|
||||
}
|
||||
%pos = %zombie.getworldboxcenter();
|
||||
%closestClient = ZombieLookForTarget(%zombie);
|
||||
%closestDistance = getWord(%closestClient,1);
|
||||
%closestClient = getWord(%closestClient,0).Player;
|
||||
if(%closestDistance <= $zombie::detectDist && %zombie.canmove != 0){
|
||||
if(%zombie.hastarget != 1){
|
||||
serverPlay3d("ZombieHOWL",%zombie.getWorldBoxCenter());
|
||||
%zombie.hastarget = 1;
|
||||
datablock ShapeBaseImageData(zLordPhotonCannonImg) {
|
||||
shapeFile = "turret_fusion_large.dts";
|
||||
emap = false;
|
||||
offset = "-1.5 0 1.0";
|
||||
};
|
||||
|
||||
datablock ForceFieldBareData(ZombieLordDefensiveBarrier) {
|
||||
className = "forcefield";
|
||||
fadeMS = 1000;
|
||||
baseTranslucency = $noPassTrans;
|
||||
powerOffTranslucency = $noPassTrans / $dimDiv;
|
||||
teamPermiable = false;
|
||||
otherPermiable = false;
|
||||
color = "0.0 1.0 0.0";
|
||||
powerOffColor = "0.0 0.0 0.0";
|
||||
targetNameTag = 'Zombie Lord Defensive Barrier';
|
||||
targetTypeTag = 'ZLordDefensiveBarrier';
|
||||
texture[0] = "skins/forcef1";
|
||||
texture[1] = "skins/forcef2";
|
||||
texture[2] = "skins/forcef3";
|
||||
texture[3] = "skins/forcef4";
|
||||
texture[4] = "skins/forcef5";
|
||||
framesPerSec = 1; // 10
|
||||
numFrames = 5;
|
||||
scrollSpeed = 15;
|
||||
umapping = 0.01; // 1.0
|
||||
vmapping = 0.01; // 0.15
|
||||
needsPower = false;
|
||||
};
|
||||
|
||||
function ZombieLordDefensiveBarrier::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType) {
|
||||
//Apply the damage to the zombie lord's energy...
|
||||
%zombie = %targetObject.sourceZombie;
|
||||
%zombie.shieldHealth -= %amount;
|
||||
//Flash the zombie lord...
|
||||
%zombie.lastShieldDamageSource = %sourceObject;
|
||||
%zombie.playShieldEffect("1 1 1");
|
||||
}
|
||||
|
||||
datablock LinearFlareProjectileData(ZLPhotonCannonProjectile) {
|
||||
scale = "4 4 4";//6
|
||||
sound = PlasmaProjectileSound;
|
||||
|
||||
faceViewer = true;
|
||||
directDamage = 0.0;
|
||||
hasDamageRadius = true;
|
||||
indirectDamage = 2.5;
|
||||
damageRadius = 10.0;
|
||||
kickBackStrength = 10000;
|
||||
radiusDamageType = $DamageType::Photon; //obviously change this
|
||||
|
||||
explosion = "PhotonMissileExplosion";
|
||||
underwaterExplosion = "PhotonMissileExplosion";
|
||||
splash = BlasterSplash;
|
||||
|
||||
dryVelocity = 500.0;
|
||||
wetVelocity = 500.0;
|
||||
velInheritFactor = 0.6;
|
||||
fizzleTimeMS = 10000;
|
||||
lifetimeMS = 10500;
|
||||
explodeOnDeath = true;
|
||||
|
||||
reflectOnWaterImpactAngle = 0.0;
|
||||
explodeOnWaterImpact = false;
|
||||
deflectionOnWaterImpact = 0.0;
|
||||
fizzleUnderwaterMS = 15000;
|
||||
|
||||
activateDelayMS = 0;
|
||||
numFlares = 35;
|
||||
flareColor = "0.0 1.1 0";
|
||||
flareModTexture = "flaremod";
|
||||
flareBaseTexture = "flarebase";
|
||||
|
||||
size[0] = 1;
|
||||
size[1] = 10;
|
||||
size[2] = 2;
|
||||
|
||||
hasLight = true;
|
||||
lightRadius = 1.0;
|
||||
lightColor = "0.6 1.1 0";
|
||||
};
|
||||
|
||||
|
||||
// Zombie Lord
|
||||
// TWM2 3.9.2
|
||||
// - Old Behavior:
|
||||
// - Heavy anti-ground assault unit that would grab and punch enemy infantry
|
||||
// - Armed with an anti-infantry acid cannon weapon
|
||||
// - New Behavior:
|
||||
// - Heavy anti-tank unit. Still grabs enemy infantry.
|
||||
// - Has preferential targeting, will try to target any available enemy ground armor before infantry.
|
||||
// - Armed with a photon cannon to hit tanks hard.
|
||||
// - When not engaged with enemy armor, will try to attack infantry. Uses weapon a lot less, but will sometimes fire.
|
||||
// - The zombie lord may sometimes engage a energy barrier to prevent enemy projectile weapons from striking itself and nearby allies.
|
||||
|
||||
function LordZombieArmor::AI(%datablock, %zombie) {
|
||||
if(!isObject(%zombie) || %zombie.getState() $= "dead") {
|
||||
if(isObject(%zombie.shieldObject)) {
|
||||
%zombie.shieldObject.delete();
|
||||
}
|
||||
return;
|
||||
}
|
||||
%chance = (getrandom() * 20);
|
||||
if(%chance >= 19)
|
||||
serverPlay3d("ZombieMoan",%zombie.getWorldBoxCenter());
|
||||
|
||||
%vector = ZgetFacingDirection(%zombie,%closestClient,%pos);
|
||||
if(%zombie.ATCount >= 20){
|
||||
%zombie.ATCount = 0;
|
||||
%zombie.nomove = 1;
|
||||
%zombie.Fire = schedule(1250, %zombie, "ZFire", %zombie, %closestClient);
|
||||
if(Game.CheckModifier("OhLordy") == 1) {
|
||||
%zombie.Fire = schedule(1750, %zombie, "ZFire", %zombie, %closestClient);
|
||||
}
|
||||
%zombie.Charge = schedule(500, %zombie, "ChargeEmitter", %zombie);
|
||||
%zombie.chargecount = 0;
|
||||
%zPos = %zombie.getPosition();
|
||||
//Are we currently in the firing weapon state?
|
||||
if(%zombie.firingWeapon) {
|
||||
%datablock.schedule(%zombie.updateTimeFrequency, "AI", %zombie);
|
||||
return;
|
||||
}
|
||||
//Check if we are currently shielding
|
||||
if(%zombie.usingShield) {
|
||||
//Is the shield broken?
|
||||
if(%zombie.shieldHealth <= 0) {
|
||||
//Yes...
|
||||
%zombie.shieldObject.delete();
|
||||
%zombie.usingShield = 0;
|
||||
if(isObject(%zombie.lastShieldDamageSource)) {
|
||||
%srcPlayer = %zombie.lastShieldDamageSource.sourceObject;
|
||||
if(isObject(%srcPlayer.client)) {
|
||||
CompleteNWChallenge(%srcPlayer.client, "ShieldBreaker");
|
||||
}
|
||||
}
|
||||
//Initialize the cooldown, note: a broken shield cooldown is 10 seconds longer than the non-broken cooldown
|
||||
TWM2Lib_Zombie_Core("setZFlag", %zombie, "canShield", 0);
|
||||
schedule(35000, 0, TWM2Lib_Zombie_Core, "setZFlag", %zombie, "canShield", 1);
|
||||
}
|
||||
%zombie.setActionThread($Zombie::RogThread, true);
|
||||
//Still going, reduce energy counter and check if we're out of energy
|
||||
%zombie.shieldEnergy--;
|
||||
if(%zombie.shieldEnergy <= 0) {
|
||||
%zombie.shieldObject.delete();
|
||||
%zombie.usingShield = 0;
|
||||
TWM2Lib_Zombie_Core("setZFlag", %zombie, "canShield", 0);
|
||||
schedule(25000, 0, TWM2Lib_Zombie_Core, "setZFlag", %zombie, "canShield", 1);
|
||||
}
|
||||
%datablock.schedule(%zombie.updateTimeFrequency, "AI", %zombie);
|
||||
return;
|
||||
}
|
||||
if(%zombie.nomove != 1) {
|
||||
%fmultiplier = $Zombie::LForwardSpeed;
|
||||
//Am I engaged with something?
|
||||
if(%zombie.hasTarget) {
|
||||
//Is it a tank?
|
||||
%tPos = %zombie.targetedPlayer.getPosition();
|
||||
if(%zombie.targetIsTank) {
|
||||
//If I'm not close enough, move up a bit
|
||||
if(!%zombie.movingToPosition) {
|
||||
if(vectorDist(%zPos, %tPos) > 200) {
|
||||
//If I'm not close enough to the target, then I need to move into range...
|
||||
%direction = vectorNormalize(vectorSub(%zPos, %tPos));
|
||||
%zombie.movePoint = vectorScale(%direction, 150);
|
||||
%zombie.movingToPosition = true;
|
||||
}
|
||||
//If I'm in range, then I need to determine my course of action
|
||||
else {
|
||||
//Fire...
|
||||
if(%zombie.canFireWeapon) {
|
||||
//LOS?
|
||||
%direction = vectorNormalize(vectorSub(%tPos, %zPos));
|
||||
%dVec = vectorAdd(%zPos, vectorscale(%direction, 200));
|
||||
%rInfo = containerRaycast(%zPos, %tPos, $AllObjMask, %zombie);
|
||||
if(getWord(%rInfo, 0) == %zombie.targetedPlayer || getWord(%rInfo, 0) == %zombie.targetedPlayer.client.vehicleMounted) {
|
||||
//Target acquired... Fire
|
||||
%datablock.zFire(%zombie, %zombie.targetedPlayer.client.vehicleMounted);
|
||||
}
|
||||
else {
|
||||
//Something's in the way... let's try moving...
|
||||
%random = vectorAdd(%zPos, TWM2Lib_MainControl("getRandomPosition", "20\t1"));
|
||||
%zombie.movePoint = %random;
|
||||
%zombie.movingToPosition = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Shield?
|
||||
if(%zombie.canShield) {
|
||||
%datablock.makeShield(%zombie);
|
||||
%zombie.setActionThread($Zombie::RogThread, true);
|
||||
}
|
||||
else {
|
||||
//For now, I can't fire or shield, move up a bit...
|
||||
%datablock.move(%zombie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//I'm currently moving to the target position, so continue moving...
|
||||
%datablock.move(%zombie);
|
||||
}
|
||||
}
|
||||
//If it's not a tank, it's a player... which is a bit easier...
|
||||
else {
|
||||
//Check the distance to the target, if we're close enough, grab it...
|
||||
%tPos = %zombie.targetedPlayer.getPosition();
|
||||
%distance = vectorDist(%zPos, %tPos);
|
||||
%vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %zombie.targetedPlayer.getPosition());
|
||||
if(%distance <= $Zombie::LordGrabDistance && %zombie.canjump == 1) {
|
||||
%vec = vectoradd(%pos,vectorScale(%vector,($Zombie::LordGrabDistance - 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 $= %zombie.targetedPlayer) {
|
||||
%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");
|
||||
%zombie.targetedPlayer.applyimpulse(%clpos, %dir);
|
||||
%zombie.targetedPlayer.damage(0, %clpos, 0.8, $DamageType::ZombieL);
|
||||
}
|
||||
else {
|
||||
%zombie.setvelocity("0 0 0");
|
||||
TWM2Lib_Zombie_Core("setZFlag", %zombie, "canJump", 0);
|
||||
schedule($Zombie::BaseJumpCooldown, 0, TWM2Lib_Zombie_Core, "setZFlag", %zombie, "canJump", 1);
|
||||
%datablock.zLordLift(%zombie, %zombie.targetedPlayer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Should I fire?
|
||||
if(%zombie.canFireWeapon && %distance > 35) {
|
||||
if(getRandom(1, 20) == 1) {
|
||||
//Fire!
|
||||
%datablock.zFire(%zombie, %zombie.targetedPlayer);
|
||||
}
|
||||
}
|
||||
//Should I shield?
|
||||
if(%zombie.canShield && %distance > 40) {
|
||||
if(getRandom(1, 35) == 1) {
|
||||
%datablock.makeShield(%zombie);
|
||||
%zombie.setActionThread($Zombie::RogThread, true);
|
||||
}
|
||||
}
|
||||
%datablock.move(%zombie);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Scan for tanks
|
||||
%targetParams = TWM2Lib_Zombie_Core("lookForTarget", %zombie, true, true);
|
||||
%target = getWord(targetParams, 0);
|
||||
%distance = getWord(%targetParams, 1);
|
||||
if(isObject(%target.player)) {
|
||||
//I see a tank, I will destroy that tank...
|
||||
if(%distance <= $zombie::detectDist) {
|
||||
%zombie.hasTarget = 1;
|
||||
%zombie.targetIsTank = true;
|
||||
%zombie.targetedPlayer = %target.player;
|
||||
}
|
||||
}
|
||||
//Scan for infantry
|
||||
%targetParams = TWM2Lib_Zombie_Core("lookForTarget", %zombie);
|
||||
%target = getWord(targetParams, 0);
|
||||
%distance = getWord(%targetParams, 1);
|
||||
if(isObject(%target.player)) {
|
||||
//Got a target player... let's go!
|
||||
if(%distance <= $zombie::detectDist) {
|
||||
%zombie.hasTarget = 1;
|
||||
%zombie.targetedPlayer = %target.player;
|
||||
}
|
||||
}
|
||||
//Nothing to hunt... random movement...
|
||||
if(!%zombie.hasTarget) {
|
||||
%zombie.zombieRmove = schedule(%zombie.updateTimeFrequency, %zombie, "TWM2Lib_Zombie_Core", "zRandomMoveLoop", %zombie);
|
||||
}
|
||||
}
|
||||
%datablock.schedule(%zombie.updateTimeFrequency, "AI", %zombie);
|
||||
}
|
||||
|
||||
function LordZombieArmor::Move(%datablock, %zombie) {
|
||||
if(!isObject(%zombie) || %zombie.getState() $= "dead") {
|
||||
return;
|
||||
}
|
||||
%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);
|
||||
}
|
||||
}
|
||||
}
|
||||
%pos = %zombie.getWorldBoxCenter();
|
||||
%chance = (getrandom() * 20);
|
||||
%mult = 1;
|
||||
if(%chance >= 19) {
|
||||
serverPlay3d("ZombieMoan", %zombie.getWorldBoxCenter());
|
||||
}
|
||||
else if(%closestDistance <= ($zombie::LKillDist + $zombie::lungDist)){
|
||||
%zombie.setvelocity("0 0 0");
|
||||
%fmultiplier = (%fmultiplier * 2.5);
|
||||
if(%zombie.movingToPosition) {
|
||||
%vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %zombie.movePoint);
|
||||
}
|
||||
%vector = vectorscale(%vector, %Fmultiplier);
|
||||
%x = Getword(%vector,0);
|
||||
%y = Getword(%vector,1);
|
||||
%z = Getword(%vector,2);
|
||||
if(%z >= 4000)
|
||||
%upvec = (%upvec * 5);
|
||||
else {
|
||||
%vector = TWM2Lib_Zombie_Core("zombieGetFacingDirection", %zombie, %zombie.targetedPlayer.getPosition());
|
||||
if(vectorDist(%pos, %zombie.targetedPlayer.getPosition()) <= ($Zombie::LordGrabDistance + $Zombie::LungeDistance)) {
|
||||
%zombie.setvelocity("0 0 0");
|
||||
%mult = 2.5;
|
||||
}
|
||||
}
|
||||
//Scale to speed
|
||||
%vector = vectorScale(vectorScale(%vector, %zombie.speed), $Zombie::SpeedMultiplier[%zombie.type]);
|
||||
%vector = vectorScale(%vector, %mult);
|
||||
%x = getWord(%vector, 0);
|
||||
%y = getWord(%vector, 1);
|
||||
%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);
|
||||
}
|
||||
%zombie.moveloop = schedule(500, %zombie, "LZombiemovetotarget", %zombie);
|
||||
%zombie.applyImpulse(%pos, %vector);
|
||||
}
|
||||
|
||||
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 LordZombieArmor::zFire(%datablock, %zombie, %targetObject) {
|
||||
if(!isObject(%zombie) || %zombie.getState() $= "dead") {
|
||||
return;
|
||||
}
|
||||
if(!isObject(%targetObject)) {
|
||||
return;
|
||||
}
|
||||
TWM2Lib_Zombie_Core("setZFlag", %zombie, "firingWeapon", 1);
|
||||
TWM2Lib_Zombie_Core("setZFlag", %zombie, "canFireWeapon", 0);
|
||||
%vec = vectorsub(%targetObject.getWorldBoxCenter(), %zombie.getMuzzlePoint(7));
|
||||
%vec = vectoradd(%vec, vectorScale(%targetObject.getVelocity(), vectorlen(%vec)/100));
|
||||
%p = new LinearFlareProjectile() {
|
||||
dataBlock = ZLPhotonCannonProjectile;
|
||||
initialDirection = %vec;
|
||||
initialPosition = %zombie.getMuzzlePoint(7);
|
||||
sourceObject = %zombie;
|
||||
sourceSlot = 7;
|
||||
};
|
||||
MissionCleanup.add(%p);
|
||||
schedule(2000, 0, "TWM2Lib_Zombie_Core", "setZFlag", %zombie, "firingWeapon", 0);
|
||||
schedule($Zombie::ZombieLordPhotonCooldown, 0, "TWM2Lib_Zombie_Core", "setZFlag", %zombie, "canFireWeapon", 1);
|
||||
}
|
||||
|
||||
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);
|
||||
function LordZombieArmor::makeShield(%datablock, %zombie) {
|
||||
if(isObject(%zombie) || %zombie.getState() $= "dead") {
|
||||
return false;
|
||||
}
|
||||
else if(%killtype == 2){
|
||||
%target.infected = 1;
|
||||
%target.damage(0, %target.getposition(), 10.0, $DamageType::ZombieL);
|
||||
if(!%zombie.canShield) {
|
||||
return false;
|
||||
}
|
||||
%count = 0;
|
||||
%zombie.canmove = 1;
|
||||
return;
|
||||
}
|
||||
%count++;
|
||||
%zombie.killingplayer = schedule(150, %zombie, "Llifttarget", %zombie, %closestclient, %count);
|
||||
%zPos = %zombie.getPosition();
|
||||
%eyePoint = posFromTransform(%zombie.getEyeTransform());
|
||||
%eVec = vectorNormalize(%zombie.getEyeVector());
|
||||
//Raycast out 25m from the eye line and make sure nothing's blocking us...
|
||||
%shieldPos = vectorAdd(%zPos, vectorScale(%eVec, 25));
|
||||
%rInfo = containerRaycast(%zPos, %shieldPos, $AllObjMask, %zombie);
|
||||
if(getWord(%rInfo, 0) != 0 && isObject(getWord(%rInfo, 0))) {
|
||||
//Something is blocking our view, cancel shield.
|
||||
return false;
|
||||
}
|
||||
//Next, find the first object we hit below the point that can serve as the shield base.
|
||||
%mask = $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType;
|
||||
%tH = getTerrainHeight(%shieldPos);
|
||||
%shieldSpawnPos = getWord(%shieldPos, 0) SPC getWord(%shieldPos, 1) spc %tH;
|
||||
%lookVector = vectorSub(%shieldSpawnPos, %eyePoint);
|
||||
%searchResult = containerRayCast(%eyePoint, %lookVector, %mask, 0);
|
||||
if(getWord(%searchResult, 0) == 0) {
|
||||
//Nothing to mount to.
|
||||
return false;
|
||||
}
|
||||
//Fetch some important parameters
|
||||
%terrPt = posFromRaycast(%searchResult);
|
||||
%terrNrm = normalFromRaycast(%searchResult);
|
||||
%intAngle = getTerrainAngle(%terrNrm); // getTerrainAngle() function found in staticShape.cs
|
||||
%rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 0 1"));
|
||||
if (getWord(%terrNrm, 2) == 1 || getWord(%terrNrm, 2) == -1) {
|
||||
%rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 1 0"));
|
||||
}
|
||||
%rotation = %rotAxis @ " " @ %intAngle;
|
||||
//We've got it all, deploy...
|
||||
%zombie.usingShield = 1;
|
||||
%zombie.shieldHealth = $Zombie::ZombieLordShieldHealth;
|
||||
%zombie.shieldEnergy = $Zombie::ZombieLordShieldEnergy;
|
||||
TWM2Lib_Zombie_Core("setZFlag", %zombie, "canShield", 0);
|
||||
//Create the shield
|
||||
%shieldObject = new (ForceFieldBare)() {
|
||||
dataBlock = ZombieLordDefensiveBarrier;
|
||||
scale = "1 1 1";
|
||||
rotation = %rotation;
|
||||
};
|
||||
MissionCleanup.add(%shieldObject);
|
||||
%zombie.shieldObject = %shieldObject;
|
||||
//Grow it over 3 seconds...
|
||||
%shieldObject.schedule(500, setRealSize, "3 1 3");
|
||||
%shieldObject.schedule(500, setTransform, %shieldObject.getTransform());
|
||||
%shieldObject.schedule(1000, setRealSize, "6 1 6");
|
||||
%shieldObject.schedule(1000, setTransform, %shieldObject.getTransform());
|
||||
%shieldObject.schedule(1500, setRealSize, "8 1 8");
|
||||
%shieldObject.schedule(1500, setTransform, %shieldObject.getTransform());
|
||||
%shieldObject.schedule(2000, setRealSize, "10 1 10");
|
||||
%shieldObject.schedule(2000, setTransform, %shieldObject.getTransform());
|
||||
%shieldObject.schedule(2500, setRealSize, "12.5 1 12.5");
|
||||
%shieldObject.schedule(2500, setTransform, %shieldObject.getTransform());
|
||||
%shieldObject.schedule(3000, setRealSize, "15 1 15");
|
||||
%shieldObject.schedule(3000, setTransform, %shieldObject.getTransform());
|
||||
}
|
||||
|
||||
function LordZombieArmor::zLordLift(%datablock, %zombie, %target, %count) {
|
||||
if(%count == 0) {
|
||||
%zombie.setMoveState(true);
|
||||
}
|
||||
if(%target.getState() $= "dead" || %zombie.getState() $= "dead"){
|
||||
%zombie.setMoveState(false);
|
||||
return;
|
||||
}
|
||||
if(!isobject(%target)) {
|
||||
%zombie.setMoveState(false);
|
||||
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.setMoveState(false);
|
||||
return;
|
||||
}
|
||||
%count++;
|
||||
%zombie.killingplayer = %datablock.schedule(150, "zLordLift", %zombie, %closestclient, %count);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue