SERVER: Revamps wunderwaffe logic

This commit is contained in:
blubs 2023-09-02 23:49:29 -07:00
parent f0e1a9c4f4
commit d156216f42
8 changed files with 496 additions and 325 deletions

View file

@ -34,6 +34,7 @@
../source/server/weapons/frames_core.qc
../source/server/weapons/rocket_launcher.qc
../source/server/weapons/ray_gun.qc
../source/server/weapons/tesla.qc
../source/server/weapons/flamethrower.qc
../source/server/weapons/grenade_launcher.qc
../source/server/weapons/weapon_core.qc

View file

@ -38,6 +38,7 @@
../source/server/weapons/frames_core.qc
../source/server/weapons/rocket_launcher.qc
../source/server/weapons/ray_gun.qc
../source/server/weapons/tesla.qc
../source/server/weapons/flamethrower.qc
../source/server/weapons/grenade_launcher.qc
../source/server/weapons/weapon_core.qc

View file

@ -139,6 +139,21 @@ void() crawler_die1 =[ 0, crawler_die2] {SetZombieHitBox(CRAWLER_BBOX);self.f
void() crawler_die2 =[ 1, crawler_die3] {self.frame = 38;};
void() crawler_die3 =[ 2, SUB_Null] {self.iszomb = 0; self.frame = 39;self.nextthink = time + 3;self.think = removeZombie; addmoney(other, 60, true); if (crawler_num > 0) {crawler_num = crawler_num - 1;}};
//====================== Crawler Tesla Death ============================
void() crawler_death_wunder1 =[ 72, crawler_death_wunder2 ] {tesla_arc(); play_sound_z(4); };
void() crawler_death_wunder2 =[ 73, crawler_death_wunder3 ] {tesla_arc(); };
void() crawler_death_wunder3 =[ 74, crawler_death_wunder4 ] {tesla_arc(); };
void() crawler_death_wunder4 =[ 75, crawler_death_wunder5 ] {tesla_arc(); };
void() crawler_death_wunder5 =[ 76, crawler_death_wunder6 ] {tesla_arc(); };
void() crawler_death_wunder6 =[ 77, crawler_death_wunder7 ] {tesla_arc(); };
void() crawler_death_wunder7 =[ 73, crawler_death_wunder8 ] {tesla_arc(); };
void() crawler_death_wunder8 =[ 74, crawler_death_wunder9 ] {tesla_arc(); };
void() crawler_death_wunder9 =[ 75, crawler_death_wunder10 ] {tesla_arc(); };
void() crawler_death_wunder10 =[ 40, SUB_Null ] {tesla_arc(); self.iszomb = 0; self.nextthink = time + 3; self.think = removeZombie;};
//======================== Climb Over Barricade ====================
//40-70
void() crawler_climbBarricade1 =[ 0, crawler_climbBarricade2] {self.movetype = MOVETYPE_STEP;self.zoom = 1;self.frame = 40;Zombie_Think();};
@ -236,6 +251,7 @@ void(entity who) makeCrawler =
who.th_melee = zombie_attack;
who.th_idle = crawler_idle1;
who.th_windowhop = crawler_climbBarricade1;
who.th_diewunder = Zombie_Tesla_Death;
who.th_fall = crawler_fall1;
who.th_land = crawler_land1;

View file

@ -85,19 +85,6 @@ $frame dogdeath1 dogdeath2
void() dog_deathanim =[ $dogdeath1, dog_deathanim2 ] {self.frame = 35;};
void() dog_deathanim2 =[ $dogdeath2, SUB_Null ] {self.nextthink = time + 3; self.think = removeZombie; self.frame = 36;};
// DOG WAFFE DEATH
// 37-46
$frame dogwunder1 dogwunder2 dogwunder3 dogwunder4 dogwunder5 dogwunder6 dogwunder7 dogwunder8 dogwunder9 dogwunder10
void() die_dog_wunder1 =[ $dogwunder1, die_dog_wunder2 ] {Zombie_Walk(0);Zombie_Tesla_Light();self.frame = 37;};
void() die_dog_wunder2 =[ $dogwunder2, die_dog_wunder3 ] {Zombie_Walk(0);self.frame = 38;};
void() die_dog_wunder3 =[ $dogwunder3, die_dog_wunder4 ] {Zombie_Walk(0);self.frame = 39;};
void() die_dog_wunder4 =[ $dogwunder4, die_dog_wunder5 ] {Zombie_Walk(0);self.frame = 40;};
void() die_dog_wunder5 =[ $dogwunder5, die_dog_wunder6 ] {Zombie_Walk(0);self.frame = 41;};
void() die_dog_wunder6 =[ $dogwunder6, die_dog_wunder7 ] {Zombie_Walk(0);Zombie_Find_Tesla_Target();self.frame = 42;};
void() die_dog_wunder7 =[ $dogwunder7, die_dog_wunder8 ] {Zombie_Walk(0);self.frame = 43;};
void() die_dog_wunder8 =[ $dogwunder8, die_dog_wunder9 ] {Zombie_Walk(0);self.frame = 44;};
void() die_dog_wunder9 =[ $dogwunder9, die_dog_wunder10 ] {Zombie_Walk(0);self.frame = 45;};
void() die_dog_wunder10 =[ $dogwunder10, die_dog_wunder10 ] {Zombie_Walk(0);self.frame = 46;self.health = 0; self.th_die();};
// DOG LIGHTNING SPAWN
// 1-13
@ -144,33 +131,38 @@ void() Dog_Think =
}
float dogCount;
void() Dog_Death =
{
self.aistatus = "0";
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
self.takedamage = DAMAGE_NO;
void(entity ent) Dog_Death_Cleanup = {
// Already dead
if(ent.aistatus == "0") {
return;
}
ent.aistatus = "0";
ent.solid = SOLID_NOT;
ent.movetype = MOVETYPE_NONE;
ent.takedamage = DAMAGE_NO;
sound(self, 5, "sounds/null.wav", 1, ATTN_NORM);
sound(ent, 5, "sounds/null.wav", 1, ATTN_NORM);
self.usedent = world;
self.health = 0;
ent.usedent = world;
ent.health = 0;
Remaining_Zombies = Remaining_Zombies - 1;
dogCount -= 1;
}
void() Dog_Death = {
Dog_Death_Cleanup(self);
play_sound_z(3);
//Gotta' make sure we set it back down instead of glitching it up, yo'
if(self.s_time > 0 && sounds_playing > 0)
{
if(self.s_time > 0 && sounds_playing > 0) {
sounds_playing --;
self.s_time = 0;
}
if (rounds == dogRound)
{
if (!Remaining_Zombies)
Spawn_Powerup(self.origin + '0 0 12', PU_MAXAMMO);
if(rounds == dogRound && Remaining_Zombies == 0) {
Spawn_Powerup(self.origin + '0 0 12', PU_MAXAMMO);
}
float r = random();
@ -178,15 +170,43 @@ void() Dog_Death =
// explode chance
if (r < 0.75 || self.electro_targeted == true) {
self.frame = 0;
setmodel (self, "models/sprites/explosion.spr");
setmodel(self, "models/sprites/explosion.spr");
sound (self, CHAN_VOICE, "sounds/weapons/grenade/explode.wav", 1, ATTN_NORM);
dog_explodeanim();
} else {
dog_deathanim();
}
};
// DOG WAFFE DEATH
// 37-46
void() dog_die_wunder1 =[ 37, dog_die_wunder2 ] {tesla_arc();};
void() dog_die_wunder2 =[ 38, dog_die_wunder3 ] {tesla_arc();};
void() dog_die_wunder3 =[ 39, dog_die_wunder4 ] {tesla_arc();};
void() dog_die_wunder4 =[ 40, dog_die_wunder5 ] {tesla_arc();};
void() dog_die_wunder5 =[ 41, dog_die_wunder6 ] {tesla_arc();};
void() dog_die_wunder6 =[ 42, dog_die_wunder7 ] {tesla_arc();};
void() dog_die_wunder7 =[ 43, dog_die_wunder8 ] {tesla_arc();};
void() dog_die_wunder8 =[ 44, dog_die_wunder9 ] {tesla_arc();};
void() dog_die_wunder9 =[ 45, dog_die_wunder10 ] {tesla_arc();};
void() dog_die_wunder10 =[ 46, SUB_Null ] {print("ayoooo\n");tesla_arc(); self.iszomb=0; self.nextthink=time+3; self.think=removeZombie;};
void() Dog_Death_Tesla = {
Dog_Death_Cleanup(self);
// TODO - place tesla spark correctly
tesla_spark(self.origin);
if(rounds == dogRound && Remaining_Zombies == 0) {
Spawn_Powerup(self.origin + '0 0 12', PU_MAXAMMO);
}
dog_die_wunder1();
};
void(entity where) spawn_a_dogB =
{
local entity sdog;//USED FOR WHAT TO SPAWN
@ -242,7 +262,7 @@ void(entity where) spawn_a_dogB =
sdog.th_melee = dog_meleeanim;
sdog.th_idle = dog_idleanim;
sdog.th_diewunder = die_dog_wunder1;
sdog.th_diewunder = Dog_Death_Tesla;
sdog.electro_targeted = 0;

View file

@ -31,6 +31,7 @@ void() Zombie_Walk_Setup;
void() crawler_rip_board1;
void() crawler_da1;
void() crawler_die1;
void() crawler_death_wunder1;
void() LinkZombiesHitbox;
@ -1027,7 +1028,7 @@ void() removeZombie =
self.flags = 0;
self.crawling = 0;
self.bleedingtime = 0;
self.iszomb = 0;
self.iszomb = 0; // 1 for alive AI, 0 for corpses / unallocated reserevd ents
self.owner = world;
self.spawnflags = 0;
@ -1095,46 +1096,55 @@ void() zombie_deathC8 =[ $deathC8, zombie_deathC9 ] {self.frame = 146;zombie_
void() zombie_deathC9 =[ $deathC9, zombie_deathC10 ] {self.frame = 147;};
void() zombie_deathC10 =[ $deathC10, SUB_Null ] {self.iszomb = 0; self.nextthink = time + 3; self.think = removeZombie; self.frame = 148;};
void() Zombie_Death =
{
self.aistatus = "0";
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
self.takedamage = DAMAGE_NO;
self.head.solid = SOLID_NOT;
self.head.movetype = MOVETYPE_NONE;
self.head.takedamage = DAMAGE_NO;
self.larm.solid = SOLID_NOT;
self.larm.movetype = MOVETYPE_NONE;
self.larm.takedamage = DAMAGE_NO;
self.rarm.solid = SOLID_NOT;
self.rarm.movetype = MOVETYPE_NONE;
self.rarm.takedamage = DAMAGE_NO;
// ...
sound(self, CHAN_WEAPON, "sounds/null.wav" ,1, ATTN_NORM);
sound(self, CHAN_VOICE, "sounds/null.wav" ,1, ATTN_NORM);
sound(self, CHAN_BODY, "sounds/null.wav" ,1, ATTN_NORM);
sound(self, CHAN_ITEM, "sounds/null.wav" ,1, ATTN_NORM);
void(entity ent) Zombie_Death_Cleanup = {
// Already dead
if(ent.aistatus == "0") {
return;
}
ent.aistatus = "0";
ent.solid = SOLID_NOT;
ent.movetype = MOVETYPE_NONE;
ent.takedamage = DAMAGE_NO;
self.usedent = world;
ent.head.solid = SOLID_NOT;
ent.head.movetype = MOVETYPE_NONE;
ent.head.takedamage = DAMAGE_NO;
ent.larm.solid = SOLID_NOT;
ent.larm.movetype = MOVETYPE_NONE;
ent.larm.takedamage = DAMAGE_NO;
ent.rarm.solid = SOLID_NOT;
ent.rarm.movetype = MOVETYPE_NONE;
ent.rarm.takedamage = DAMAGE_NO;
sound(ent, CHAN_WEAPON, "sounds/null.wav" ,1, ATTN_NORM);
sound(ent, CHAN_VOICE, "sounds/null.wav" ,1, ATTN_NORM);
sound(ent, CHAN_BODY, "sounds/null.wav" ,1, ATTN_NORM);
sound(ent, CHAN_ITEM, "sounds/null.wav" ,1, ATTN_NORM);
if(self.goalentity.classname == "window")
ent.usedent = world;
if(ent.goalentity.classname == "window")
{
if(self.goalentity.box1owner == self)
self.goalentity.box1owner = world;
if(self.goalentity.box2owner == self)
self.goalentity.box2owner = world;
if(self.goalentity.box3owner == self)
self.goalentity.box3owner = world;
if(self.goalentity.usedent == self)
self.goalentity.usedent = world;
if(ent.goalentity.box1owner == ent)
ent.goalentity.box1owner = world;
if(ent.goalentity.box2owner == ent)
ent.goalentity.box2owner = world;
if(ent.goalentity.box3owner == ent)
ent.goalentity.box3owner = world;
if(ent.goalentity.usedent == ent)
ent.goalentity.usedent = world;
}
self.health = 0;
ent.health = 0;
Remaining_Zombies = Remaining_Zombies - 1;
}
void() Zombie_Death =
{
Zombie_Death_Cleanup(self);
// Death Noises
if (self.electro_targeted == false)
@ -1174,7 +1184,7 @@ void() Zombie_Death =
{
zombie_deathA1();
}
else if(random() < 0.6)
else if(random() < 0.5)
{
zombie_deathB1();
}
@ -1190,7 +1200,6 @@ void() Zombie_Death =
// Electric Damage
// --------------------
//
void() Zombie_Tesla_Light;
//
// Z_ElectroShock
@ -1206,7 +1215,13 @@ void() Z_ElectroShock =
self.death_timer_activated = true;
// Spawn a Sparkle
Zombie_Tesla_Light();
if(self.crawling == true) {
tesla_spark(self.origin - '0 0 18');
}
else {
tesla_spark(self.origin + '0 0 13');
}
// Zombie_Tesla_Light();
// Decide what to Gib
float r = random();
@ -1256,129 +1271,48 @@ void() Z_ElectroShock =
/////////////////////ZOMBIE WAFFE STUFF/////////////////////
void() Zombie_Lightning_Think =
{
self.frame++;
if (self.frame >= 3)
self.frame = 0;
// suicide timer!
if(self.ltime < time) {
remove(self);
}
self.nextthink = time + 0.05;
}
void() Zombie_Tesla_Light =
{
// lightning sprite
local entity lightning = spawn();
setmodel(lightning, "models/sprites/lightning.spr");
setorigin(lightning, self.origin + '0 0 13');
lightning.think = Zombie_Lightning_Think;
lightning.nextthink = time + 0.05;
lightning.ltime = time + 1;
}
void() Zombie_Find_Tesla_Target =
{
entity zombs = findradius(self.origin, 200);
entity tempe;
vector org;
vector targetorg;
float break_loop;
if (self.teslacount > 10)
return;
break_loop = false;
while(break_loop == false) {
if (zombs == world) {
break_loop = true;
continue;
}
if (zombs.classname == "ai_zombie" || zombs.classname == "ai_dog") {
break_loop = true;
zombs.firer = self.firer;
// remove libs
if (zombs.head)
setmodel(zombs.head, "");
if (zombs.larm)
setmodel(zombs.larm, "");
if (zombs.rarm)
setmodel(zombs.rarm, "");
// add 50pts
addmoney(self.firer, 50, true);
// kill
self.firer.kills += 1;
// add to tesla count
zombs.teslacount = self.teslacount + 1;
// classname change
zombs.classname = "wunder";
zombs.head.classname = zombs.larm.classname =
zombs.rarm.classname = "wunder_limb";
// just to be extra careful
zombs.takedamage = zombs.head.takedamage =
zombs.larm.takedamage = zombs.rarm.takedamage = DAMAGE_NO;
org = self.origin + '0 0 13';
targetorg = zombs.origin + '0 0 13';
// shoot lightning
#ifdef FTE
te_lightning2(self, org, targetorg);
#else
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
WriteCoord (MSG_BROADCAST, targetorg_x);
WriteCoord (MSG_BROADCAST, targetorg_y);
WriteCoord (MSG_BROADCAST, targetorg_z);
#endif // FTE
// anim play
tempe = self;
self = zombs;
self.th_diewunder();
self = tempe;
}
zombs = zombs.chain;
}
}
// Wunder'd
// 149-152 (FIXME - animate wunder'd zombies)
$frame wunder1 wunder2 wunder3 wunder4 wunder5 wunder6 wunder7 wunder8 wunder9 wunder10
void() zombie_wunder1 =[ $wunder1, zombie_wunder2 ] {play_sound_z(4);Zombie_Tesla_Light();Zombie_Walk(0);self.frame = 149;self.solid = SOLID_NOT;};
void() zombie_wunder2 =[ $wunder2, zombie_wunder3 ] {Zombie_Walk(0);self.frame = 150;};
void() zombie_wunder3 =[ $wunder3, zombie_wunder4 ] {Zombie_Walk(0);Zombie_Find_Tesla_Target();self.frame = 151;};
void() zombie_wunder4 =[ $wunder4, zombie_wunder5 ] {Zombie_Walk(0);self.frame = 152;};
void() zombie_wunder5 =[ $wunder5, zombie_wunder6 ] {Zombie_Walk(0);self.frame = 151;};
void() zombie_wunder6 =[ $wunder6, zombie_wunder7 ] {Zombie_Walk(0);self.frame = 152;};
void() zombie_wunder7 =[ $wunder7, zombie_wunder8 ] {Zombie_Walk(0);self.frame = 151;};
void() zombie_wunder8 =[ $wunder8, zombie_wunder9 ] {play_sound_z(3);Zombie_Walk(0);self.frame = 152;};
void() zombie_wunder9 =[ $wunder9, zombie_wunder10 ] {Zombie_Walk(0);self.frame = 151;};
void() zombie_wunder10 =[ $wunder10, SUB_Null ] {self.health = 0; self.th_die();Zombie_Walk(0);self.frame = 152;};
void() zombie_wunder1 =[ $wunder1, zombie_wunder2 ] {tesla_arc(); play_sound_z(4); self.frame = 149;};
void() zombie_wunder2 =[ $wunder2, zombie_wunder3 ] {tesla_arc(); self.frame = 150;};
void() zombie_wunder3 =[ $wunder3, zombie_wunder4 ] {tesla_arc(); self.frame = 151;};
void() zombie_wunder4 =[ $wunder4, zombie_wunder5 ] {tesla_arc(); self.frame = 152;};
void() zombie_wunder5 =[ $wunder5, zombie_wunder6 ] {tesla_arc(); self.frame = 151;};
void() zombie_wunder6 =[ $wunder6, zombie_wunder7 ] {tesla_arc(); self.frame = 152;};
void() zombie_wunder7 =[ $wunder7, zombie_wunder8 ] {tesla_arc(); self.frame = 151;};
void() zombie_wunder8 =[ $wunder8, zombie_wunder9 ] {tesla_arc(); play_sound_z(3); self.frame = 152;};
void() zombie_wunder9 =[ $wunder9, zombie_wunder10 ] {tesla_arc(); self.frame = 151;};
void() zombie_wunder10 =[ $wunder10, SUB_Null ] {
tesla_arc(); self.iszomb = 0; self.nextthink = time + 3; self.think = removeZombie;self.frame = 152;
// Play final death anim:
if(random() < 0.3) {
zombie_deathA1();
}
else if(random() < 0.5) {
zombie_deathB1();
}
else {
zombie_deathC1();
}
};
void() Zombie_Tesla_Death = {
Zombie_Death_Cleanup(self);
if(self.crawling == true) {
tesla_spark(self.origin - '0 0 18');
crawler_death_wunder1();
}
else {
tesla_spark(self.origin + '0 0 13');
zombie_wunder1();
}
};
/////////////////////ZOMBIE SPAWNING/////////////////////
void() zombieRise =
@ -1551,12 +1485,11 @@ void(float i) spawnSingleZombEnt =
zSpawn.rarm.takedamage = DAMAGE_NO;
#ifndef FTE
updateLimb (zSpawn, 2, zSpawn.rarm);
#endif
#endif // FTE
};
void(entity szombie) SetUpHitBoxes =
{
szombie.head.solid = SOLID_CORPSE;
@ -1740,7 +1673,7 @@ void(entity where) spawn_a_zombieB =
szombie.th_fall = zombie_fall1;
szombie.th_land = zombie_land1;
szombie.th_diewunder = zombie_wunder1;
szombie.th_diewunder = Zombie_Tesla_Death;
//szombie.th_jump = zombie_jump1;
//szombie.th_grabledge = zombie_grabledge1;

View file

@ -149,6 +149,7 @@ void() W_SprintStop;
void SwitchWeapon(float to);
void GetUp();
void Weapon_Logic();
void (float shotcount, float sprd, float Damage, float side) FireTrace;
.float downed;
.float fire_delay;
.float fire_delay2;
@ -275,7 +276,18 @@ float zombie_spawn_timer; // the actual timer for spawn delay
.vector idlebox;
.vector hop_spot;//used for windows (zombies hop to these)
.vector goalorigin;
.float teslacount;
.float teslacount; // TODO - Remove this
.float tesla_n_kills; // Player - Number of kills remaining for the current tesla shot
.float tesla_next_arc_time; // Zombie - Time at which zombie should try arcing
.float tesla_arc_num; // Zombie - current arc number
.entity tesla_arc_parent; // Zombie - Track the entity that we arced from
.entity tesla_arc_owner; // Zombie - Player ent that fired the tesla
void(vector pos) tesla_spark;
.float iszomb;
.float onfire;
.entity firer;

View file

@ -0,0 +1,319 @@
/*
server/weapons/tesla.qc
Core logic for the Wunderwaffe special weapon.
Copyright (C) 2021-2022 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
//
// Think function for tesla spark sprite spawned at zombie torso
//
void() tesla_spark_think =
{
float prev_frame = self.frame;
while(self.frame == prev_frame) {
self.frame = rint(random()*3);
}
if(self.ltime < time) {
remove(self);
}
self.nextthink = time + 0.05;
}
//
// Tesla spark sprite spawned at zombie torso
//
void(vector pos) tesla_spark = {
local entity lightning = spawn();
setmodel(lightning, "models/sprites/lightning.spr");
setorigin(lightning, pos);
lightning.think = tesla_spark_think;
lightning.nextthink = time + 0.05;
lightning.ltime = time + 1;
}
//
//
//
void(entity hit_ent, entity arc_parent, entity arc_owner, float arc_num, float do_arc) tesla_damage = {
// set lib models to null
// (if we remove them RelinkZombies will cry)
if (hit_ent.head)
setmodel(hit_ent.head, "");
if (hit_ent.larm)
setmodel(hit_ent.larm, "");
if (hit_ent.rarm)
setmodel(hit_ent.rarm, "");
hit_ent.velocity.x = 0;
hit_ent.velocity.y = 0;
// window hop fix
if (self.state == 1 || self.hop_step != 0) {
self.state = self.hop_step = 0;
}
// // change classname so it can't be re-targted
// hit_ent.classname = "wunder";
if(arc_owner != world) {
arc_owner.tesla_n_kills += 1;
// 50 points for waffe kills
if(arc_owner.classname == "player") {
addmoney(arc_owner, 50, true);
}
}
if(do_arc == true) {
// float wait_time = lerp(0.2,0.6, random()) * arc_num;
// The first zombie does not wait, every arc thereafter does
float wait_time = arc_num == 1 ? 0 : lerp(0.2,0.6, random()) * arc_num;
hit_ent.tesla_next_arc_time = time + wait_time;
// print("Entity ", hit_ent.classname, " set to arc after ",ftos(wait_time)," (t=", ftos(hit_ent.tesla_next_arc_time), ")\n");
}
else {
// print("Entity ", hit_ent.classname, " NOT set to arc at.\n");
hit_ent.tesla_next_arc_time = -1;
}
hit_ent.tesla_arc_parent = arc_parent;
hit_ent.tesla_arc_owner = arc_owner;
hit_ent.tesla_arc_num = arc_num;
// play our wunder-ful anim
entity oself = self;
self = hit_ent;
self.th_diewunder();
self = oself;
}
vector(entity ent) tesla_arc_ofs_for_ent = {
if(ent.classname == "ai_zombie") {
if(ent.crawling == true) {
return '0 0 -18';
}
else {
return '0 0 20';
}
}
else if(ent.classname == "ai_dog") {
return '0 0 0';
}
return '0 0 0';
}
// entity cur_ent, entity prev_ent, entity player
void() tesla_arc = {
if(self.tesla_next_arc_time < 0) {
return;
}
if(self.tesla_next_arc_time > time) {
return;
}
// print("\"",self.classname,"\" arcing ( arcs:",ftos(self.tesla_arc_num)," kills: ",ftos(self.tesla_arc_owner.tesla_n_kills),") for arctime: ");
// print(ftos(self.tesla_next_arc_time),"\n");
self.tesla_next_arc_time = -1;
if(self.tesla_arc_owner.tesla_n_kills >= 10) {
// print("\tAt max kills. Stopping.\n");
return;
}
self.iszomb = 0;
// If we can't arc any further, tell parent to keep trying
if(self.tesla_arc_num >= 5) {
// We already waited, do it immediately
self.tesla_arc_parent.tesla_next_arc_time = 0;
// print("\tAt max arc-counts, keep arcing from parent.\n");
return;
}
// Maximum arcing distance for this zombie
float max_dist = 300 - (20 * self.tesla_arc_num);
// print("\tZombie arc to max dist: ", ftos(max_dist), "\n");
entity best_ent = world;
if(max_dist > 0) {
// If arcing, find the closest zombie to current zombie:
entity ent = findfloat(world, iszomb, 1);
float dist;
float best_dist = max_dist;
while(ent != world) {
if(ent != self && ent.aistatus == "1") {
dist = vlen(self.origin - ent.origin);
if(dist < best_dist) {
// Check traceline to make sure is visible
vector trace_start = self.origin + tesla_arc_ofs_for_ent(self);
vector trace_end = ent.origin + tesla_arc_ofs_for_ent(self);
traceline(trace_start, trace_end, MOVE_NOMONSTERS, world);
if(trace_fraction >= 1.0) {
best_dist = dist;
best_ent = ent;
}
}
}
ent = findfloat(ent, iszomb, 1);
}
}
// print("\tZombie arcing to entity: \"", best_ent.classname, "\" dist: ", ftos(best_dist), "\n");
// We found a zombie to arc to, continue arc from there
if(best_ent != world) {
tesla_damage(best_ent, self, self.tesla_arc_owner, self.tesla_arc_num + 1, true);
vector source_pos = self.origin + tesla_arc_ofs_for_ent(self);
vector target_pos = best_ent.origin + tesla_arc_ofs_for_ent(best_ent);
#ifdef FTE
te_lightning1(self, source_pos, target_pos);
#else
WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte(MSG_BROADCAST, TE_LIGHTNING1);
WriteEntity(MSG_BROADCAST, self);
WriteCoord(MSG_BROADCAST, source_pos.x);
WriteCoord(MSG_BROADCAST, source_pos.y);
WriteCoord(MSG_BROADCAST, source_pos.z);
WriteCoord(MSG_BROADCAST, target_pos.x);
WriteCoord(MSG_BROADCAST, target_pos.y);
WriteCoord(MSG_BROADCAST, target_pos.z);
#endif // FTE
}
// No ent to arc to, tell arc parent to resume its search
// else if(self.tesla_arc_parent != world) {
// // Don't wait, start immediately
// self.tesla_arc_parent.tesla_next_arc_time = 0;
// }
// Have self immediately arc again next frame
self.tesla_next_arc_time = 0;
}
// Fire lightning out of the gun
void() W_FireTesla =
{
vector source;
source = self.origin + self.view_ofs;
makevectors(self.v_angle);
vector barrel_ofs = '5.560 -3 30';
source += v_right * barrel_ofs.x;
source += v_up * barrel_ofs.y;
source += v_forward * barrel_ofs.z;
#ifdef FTE
self.dimension_hit = HITBOX_DIM_LIMBS | HITBOX_DIM_ZOMBIES;
#endif // FTE
FireTrace(1, 0, 0, 0);
#ifdef FTE
self.dimension_hit = HITBOX_DIM_ZOMBIES;
#endif // FTE
#ifdef FTE
te_lightning1(world, source, trace_endpos);
#else
WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte(MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity(MSG_BROADCAST, self);
WriteCoord(MSG_BROADCAST, source_x);
WriteCoord(MSG_BROADCAST, source_y);
WriteCoord(MSG_BROADCAST, source_z);
WriteCoord(MSG_BROADCAST, trace_endpos_x);
WriteCoord(MSG_BROADCAST, trace_endpos_y);
WriteCoord(MSG_BROADCAST, trace_endpos_z);
#endif // FTE
self.tesla_n_kills = 0;
entity hit_ent = trace_ent;
if(hit_ent.classname == "ai_zombie_head" || hit_ent.classname == "ai_zombie_larm" || hit_ent.classname == "ai_zombie_rarm")
hit_ent = hit_ent.owner;
// print("W_FireTesla hit ent: ", hit_ent.classname, "\n");
if(trace_ent != world && trace_ent.takedamage) {
tesla_damage(hit_ent, world, self, 1, true);
}
// Not a direct-hit, do splash damage:
else {
tesla_spark(trace_endpos);
// TODO - Search for proximity to players and damage players
// TODO - Electric overlay player HUD
// ------- Find zombie closest to splash damage pos ---------
// Damage any players within splash damage radius along the way
float inner_radius = 30;
float splash_radius = 110;
entity ent = findradius(trace_endpos, splash_radius);
float dist;
entity best_ent = world;
float best_dist = splash_radius;
while(ent != world) {
if(ent == self) {
// ----------------------------------------
// Player logic:
// ----------------------------------------
// - Same damage with or without jug
// - Deal 75 damage at `inner_radius` qu
// - Deal 0 damage at `splash_radius` qu
// - Linearly interpolate damage in-between
dist = vlen(ent.origin - trace_endpos);
// lerp_frac: 1 at inner_radius, 0 at splash_radius
float lerp_frac = (dist - splash_radius) / (inner_radius - splash_radius);
float damage = lerp(0, 75, lerp_frac);
// print("Giving player ",ftos(damage), " damage.\n");
if (other.perks & P_JUG)
DamageHandler(ent, self, damage, S_ZAPPER);
else
DamageHandler(ent, self, damage, S_ZAPPER);
// ----------------------------------------
}
if(ent.aistatus == "1") {
dist = vlen(ent.origin - trace_endpos);
if(dist < best_dist) {
best_dist = dist;
best_ent = ent;
}
}
ent = ent.chain;
}
if(best_ent != world) {
tesla_damage(best_ent, world, self, 1, true);
}
}
}

View file

@ -1033,137 +1033,6 @@ void (float shotcount, float sprd, float Damage, float side) FireTrace =
}
// Remove zombie, add money, request clone spawn.
void(entity hit_ent) LightningHit =
{
local entity tempe;
// 50 points for waffe kills
addmoney(self, 50, true);
// set lib models to null
// (if we remove them RelinkZombies will cry)
if (hit_ent.head)
setmodel(hit_ent.head, "");
if (hit_ent.larm)
setmodel(hit_ent.larm, "");
if (hit_ent.rarm)
setmodel(hit_ent.rarm, "");
// window hop fix
if (self.state == 1 || self.hop_step != 0) {
self.state = self.hop_step = 0;
}
// change classname so it can't be re-targted
hit_ent.classname = "wunder";
// own it!
hit_ent.firer = self;
// we're the start of a chain
hit_ent.teslacount = 1;
// play our wunder-ful anim
tempe = self;
self = hit_ent;
self.th_diewunder();
self = tempe;
// kill
self.kills += 1;
};
// Initial Zombie impact, creds to Naievil/UP
void(vector p1, vector p2, entity from, float damage) LightningDamage =
{
local entity e1, e2;
local vector f;
entity hit_ent;
f = p2 - p1;
normalize (f);
f_x = 0 - f_y;
f_y = f_x;
f_z = 0;
f = f*16;
e1 = e2 = world;
//traceline (p1, p2, false, self);
hit_ent = trace_ent;
if (hit_ent == world)
return;
if (hit_ent.classname == "ai_zombie_head" || hit_ent.classname == "ai_zombie_larm" || hit_ent.classname == "ai_zombie_rarm")
hit_ent = hit_ent.owner;
if (trace_ent.takedamage)
{
LightningHit (hit_ent);
}
e1 = trace_ent;
traceline (p1 + f, p2 + f, FALSE, self);
if (trace_ent != e1 && trace_ent.takedamage)
{
LightningHit (hit_ent);
}
e2 = trace_ent;
traceline (p1 - f, p2 - f, FALSE, self);
if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
{
LightningHit (hit_ent);
}
};
// Fire lightning out of the gun
void() W_FireTesla =
{
vector source;
makevectors (self.v_angle);
source = self.origin + self.view_ofs;
#ifdef FTE
self.dimension_hit = HITBOX_DIM_LIMBS | HITBOX_DIM_ZOMBIES;
#endif // FTE
FireTrace(1, 0, 0, 0);
#ifdef FTE
self.dimension_hit = HITBOX_DIM_ZOMBIES;
#endif // FTE
#ifdef FTE
te_lightning2(self, source, trace_endpos);
#else
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, source_x);
WriteCoord (MSG_BROADCAST, source_y);
WriteCoord (MSG_BROADCAST, source_z);
WriteCoord (MSG_BROADCAST, trace_endpos_x);
WriteCoord (MSG_BROADCAST, trace_endpos_y);
WriteCoord (MSG_BROADCAST, trace_endpos_z);
#endif // FTE
LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
}
void(float side) W_Fire =
{