607 lines
14 KiB
C++
607 lines
14 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
$Header: /HexenWorld/Siege/lightwp.hc 22 5/25/98 1:39p Mgummelt $
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
// For building the model
|
|
$cd Q:\art\models\weapons\spllbook
|
|
$origin 0 0 0
|
|
$base BASE skin
|
|
$skin skin
|
|
$flags 0
|
|
|
|
//
|
|
$frame fidle1 fidle2 fidle3 fidle4 fidle5
|
|
$frame fidle6 fidle7 fidle8 fidle9 fidle10
|
|
$frame fidle11 fidle12 fidle13 fidle14 fidle15
|
|
$frame fidle16
|
|
|
|
//
|
|
$frame nidle1 nidle2 nidle3 nidle4 nidle5
|
|
$frame nidle6 nidle7 nidle8 nidle9 nidle10
|
|
$frame nidle11 nidle12 nidle13 nidle14 nidle15
|
|
$frame nidle16
|
|
|
|
//
|
|
$frame normal1 normal2 normal3 normal4 normal5
|
|
$frame normal6 normal7 normal8 normal9 normal10
|
|
$frame normal11 normal12 normal13 normal14 normal15
|
|
$frame normal16
|
|
|
|
//
|
|
$frame pidle1 pidle2 pidle3 pidle4 pidle5
|
|
$frame pidle6 pidle7 pidle8 pidle9 pidle10
|
|
$frame pidle11 pidle12 pidle13 pidle14 pidle15
|
|
$frame pidle16
|
|
|
|
//
|
|
$frame power1 power2 power3 power4 power5
|
|
$frame power6 power7 power8 power9 power10
|
|
$frame power11 power12 power13 power14 power15
|
|
$frame power16
|
|
|
|
//
|
|
$frame select1 select2 select3 select4 select5
|
|
$frame select6 select7 select8 select9 select10
|
|
$frame select11 select12
|
|
|
|
|
|
/*
|
|
======================
|
|
Lightning Bolts Test
|
|
|
|
Unpowered: Ball Lightning
|
|
|
|
Powered: Chain lightning- arcs between monsters
|
|
======================
|
|
*/
|
|
|
|
void lball_remove ()
|
|
{
|
|
stopSound(self,0);
|
|
remove(self);
|
|
}
|
|
|
|
void LightningBallTouch ()
|
|
{
|
|
float zap_other;
|
|
|
|
if(other.classname==self.classname&&other.owner==self.owner)
|
|
return;
|
|
|
|
self.level=FALSE;
|
|
if(other.takedamage)
|
|
{
|
|
T_Damage(other,self,self.owner,self.dmg);
|
|
if(other.flags&FL_MONSTER)
|
|
zap_other=TRUE;
|
|
}
|
|
self.dmg = random(70, 100);
|
|
T_RadiusDamage(self,self.owner,self.dmg,other);
|
|
// stopSound(self,0);
|
|
// sound(self,CHAN_AUTO,"crusader/lghtn2.wav",1,ATTN_NORM);
|
|
// starteffect(CE_LBALL_EXPL,self.origin-self.movedir*8,0.05);
|
|
/* if(zap_other)
|
|
{
|
|
org=self.origin;
|
|
tospot=normalize((other.absmin+other.absmax)*0.5-org);
|
|
tospot=org+tospot*(random(75)+75);
|
|
//do_lightning (self.owner,zap_cnt,0,4,org,tospot,100,TE_STREAM_LIGHTNING);
|
|
|
|
damage_dir=normalize(tospot-org);
|
|
LightningDamage (org-damage_dir*15, tospot+damage_dir*15, self.owner, 100,"lightning");
|
|
}
|
|
|
|
while(zap_cnt<3)//8)
|
|
{
|
|
self.angles=randomv('0 0 0','360 360 360');
|
|
makevectors(self.angles);
|
|
org=self.origin;
|
|
tospot=org+v_forward*(random(75)+75);
|
|
//do_lightning (self.owner,zap_cnt,0,4,org,tospot,50,TE_STREAM_LIGHTNING);
|
|
|
|
damage_dir=normalize(tospot-org);
|
|
LightningDamage (org-damage_dir*15, tospot+damage_dir*15, self.owner, 100,"lightning");
|
|
|
|
zap_cnt+=1;
|
|
}*/
|
|
WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_MULTICAST, TE_LIGHTNINGEXPLODE);
|
|
WriteEntity (MSG_MULTICAST, self.owner);
|
|
WriteCoord (MSG_MULTICAST, self.origin_x);
|
|
WriteCoord (MSG_MULTICAST, self.origin_y);
|
|
WriteCoord (MSG_MULTICAST, self.origin_z);
|
|
multicast(self.origin,MULTICAST_PHS_R);
|
|
|
|
remove(self);
|
|
}
|
|
|
|
void lightningHomeThink()
|
|
{
|
|
vector moveAng;
|
|
|
|
HomeThink();
|
|
|
|
moveAng = vectoangles(self.velocity);
|
|
|
|
traceline(self.origin, self.origin + self.velocity*.2, FALSE, self);
|
|
|
|
WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_MULTICAST, TE_LIGHTNINGBALL);
|
|
WriteCoord (MSG_MULTICAST, self.origin_x);
|
|
WriteCoord (MSG_MULTICAST, self.origin_y);
|
|
WriteCoord (MSG_MULTICAST, self.origin_z);
|
|
WriteByte (MSG_MULTICAST, moveAng_y*256.0/360.0);
|
|
WriteByte (MSG_MULTICAST, moveAng_x*256.0/360.0);
|
|
WriteShort(MSG_MULTICAST, vlen(self.velocity));
|
|
WriteByte (MSG_MULTICAST, trace_fraction * 100);
|
|
multicast(self.origin,MULTICAST_PVS);
|
|
|
|
thinktime self : 0.2;
|
|
|
|
if (self.lifetime < time)
|
|
SUB_Remove();
|
|
}
|
|
|
|
void FireLightningBall ()
|
|
{
|
|
entity lball;
|
|
|
|
makevectors(self.v_angle);
|
|
self.effects(+)EF_MUZZLEFLASH;
|
|
stuffcmd (self, "bf\n");
|
|
lball=spawn();
|
|
lball.classname="lightning ball";
|
|
lball.owner=self;
|
|
lball.drawflags(+)SCALE_ORIGIN_CENTER;
|
|
lball.movetype=MOVETYPE_FLYMISSILE;
|
|
lball.solid=SOLID_BBOX;
|
|
lball.level=TRUE;
|
|
|
|
lball.touch=LightningBallTouch;
|
|
lball.dmg=random(60,100);
|
|
|
|
lball.speed=1000;
|
|
lball.velocity=normalize(v_forward)*lball.speed;
|
|
lball.angles=randomv('-600 -600 -600','600 600 600');
|
|
|
|
setmodel(lball,"models/lball.mdl");
|
|
setsize(lball,'0 0 0','0 0 0');
|
|
|
|
lball.scale=0.75;
|
|
setorigin(lball,self.origin+self.proj_ofs+v_forward*10);
|
|
// sound(self,CHAN_AUTO,"succubus/firelbal.wav",1,ATTN_NORM);
|
|
|
|
lball.turn_time=2;
|
|
// lball.dmg=random(45,55);
|
|
lball.effects=EF_DIMLIGHT|EF_UPDATESOUND;
|
|
lball.frags=TRUE;
|
|
lball.veer=100;
|
|
lball.homerate=0.1;
|
|
lball.lifetime=time+2.5;
|
|
lball.th_die=lball_remove;
|
|
//lball.think=HomeThink;
|
|
lball.hoverz=TRUE;
|
|
//thinktime lball : 0.2;
|
|
lball.t_width=time+random(0.02,0.5);
|
|
// sound(lball,CHAN_UPDATE+PHS_OVERRIDE_R,"succubus/buzz2.wav",1,ATTN_LOOP);
|
|
|
|
lball.effects(+)EF_NODRAW;
|
|
|
|
entity oldself;
|
|
oldself = self;
|
|
self = lball;
|
|
|
|
lball.think = lightningHomeThink;
|
|
lball.think();
|
|
|
|
self = oldself;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LilLightningThink()
|
|
{
|
|
T_Damage(self.enemy, self.owner, self.owner, self.dmg);
|
|
|
|
remove(self);
|
|
}
|
|
|
|
void AttachLilLightning(float damage, entity nTarg, entity from)
|
|
{
|
|
entity newGuy;
|
|
|
|
newGuy = spawn();
|
|
newGuy.effects (+) EF_NODRAW;
|
|
|
|
newGuy.dmg = damage;
|
|
newGuy.owner = from;
|
|
newGuy.enemy = nTarg;
|
|
|
|
newGuy.think = LilLightningThink;
|
|
thinktime newGuy : 0.0;
|
|
}
|
|
|
|
void(vector p1, vector p2, entity from, float damage) LightningDamage2 =
|
|
{
|
|
entity e1, e2;// swap;
|
|
vector f;
|
|
float inertia;//absorb;
|
|
|
|
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);
|
|
|
|
if (trace_ent.takedamage)
|
|
{
|
|
if (trace_ent.mass<=10)
|
|
{
|
|
inertia=1;
|
|
}
|
|
else
|
|
{
|
|
inertia = trace_ent.mass/10;
|
|
}
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_x);
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_y);
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_z + 32);
|
|
AttachLilLightning(damage, trace_ent, from);
|
|
}
|
|
|
|
e1 = trace_ent;
|
|
traceline (p1 + f, p2 + f, FALSE, self);
|
|
if(trace_ent != e1 && trace_ent.takedamage)
|
|
{
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_x);
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_y);
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_z + 32);
|
|
AttachLilLightning(damage, trace_ent, from);
|
|
}
|
|
|
|
e2 = trace_ent;
|
|
traceline (p1 - f, p2 - f, FALSE, self);
|
|
if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
|
|
{
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_x);
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_y);
|
|
WriteCoord(MSG_MULTICAST, trace_ent.origin_z + 32);
|
|
AttachLilLightning(damage, trace_ent, from);
|
|
}
|
|
};
|
|
|
|
void do_lightning2 (entity lowner,float tag, float lflags, float duration, vector spot1, vector spot2, float ldamg)
|
|
{
|
|
vector damage_dir;
|
|
|
|
// lowner=self.owner;
|
|
|
|
damage_dir=normalize(spot2-spot1);
|
|
LightningDamage2 (spot1-damage_dir*15, spot2+damage_dir*15, lowner, ldamg);
|
|
}
|
|
|
|
void branch_fire (vector org)
|
|
{
|
|
vector tospot, lightn_dir;
|
|
float num_branches;
|
|
|
|
tospot=org+v_forward*1000;
|
|
traceline(org,tospot,TRUE,self);
|
|
tospot=trace_endpos;
|
|
|
|
num_branches = 3;
|
|
self.count=0;
|
|
while(num_branches)
|
|
{
|
|
self.count+=1;
|
|
if(self.count>=8)
|
|
self.count=0;
|
|
|
|
do_lightning2 (self,self.count,STREAM_ATTACHED,4,org,tospot,30);
|
|
|
|
lightn_dir=normalize(tospot-org);
|
|
org=org + lightn_dir*random(num_branches+20,num_branches+45);//Include trace_fraction?
|
|
tospot=org+v_forward*1000;
|
|
traceline(trace_endpos,tospot,TRUE,self);
|
|
tospot=trace_endpos;
|
|
if(random()<0.5)
|
|
tospot+=v_right*random(150,400);
|
|
else
|
|
tospot-=v_right*random(150,400);
|
|
if(random()<0.5)
|
|
tospot+=v_up*random(150,400);
|
|
else
|
|
tospot-=v_up*random(150,400);
|
|
|
|
num_branches-=1;
|
|
}
|
|
}
|
|
|
|
void shebitch_chain_lightning_strike ()
|
|
{
|
|
vector org, tospot;
|
|
float damg,damg_thresh, zap_count,fov_check;
|
|
entity loser, lastloser,firstloser;
|
|
float numTargs;
|
|
|
|
numTargs = 0;
|
|
|
|
if(self.attack_finished>time)
|
|
return;
|
|
self.greenmana-=4;
|
|
self.bluemana-=4;
|
|
self.attack_finished=time+0.2;
|
|
self.effects(+)EF_MUZZLEFLASH;
|
|
makevectors(self.v_angle);
|
|
org=self.origin+self.proj_ofs+v_forward*36;
|
|
|
|
loser=findradius(org,1000);
|
|
firstloser=lastloser=loser;
|
|
|
|
WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_MULTICAST, TE_CHAINLIGHTNING);
|
|
WriteEntity(MSG_MULTICAST, self);
|
|
|
|
WriteCoord(MSG_MULTICAST, org_x);
|
|
WriteCoord(MSG_MULTICAST, org_y);
|
|
WriteCoord(MSG_MULTICAST, org_z);
|
|
|
|
while((loser!=world)&&(numTargs < 5))
|
|
{
|
|
if(loser.health&&loser.flags2&FL_ALIVE&&loser!=self)
|
|
{
|
|
tospot=(loser.absmin+loser.absmax)*0.5;
|
|
traceline(org,tospot,TRUE,self);
|
|
if(infront(loser))
|
|
{
|
|
if(lastloser==firstloser)
|
|
{
|
|
fov_check=vlen(loser.origin-self.origin);
|
|
fov_check=(50/fov_check);
|
|
if(fov_check>1)
|
|
fov_check=1;
|
|
fov_check*=10;//at further distances, cone is smaller
|
|
if(!fov(loser,self,fov_check))
|
|
trace_fraction=0;
|
|
}
|
|
}
|
|
else
|
|
trace_fraction=0;
|
|
|
|
if(trace_fraction==1)
|
|
{
|
|
if(loser.flags&FL_MONSTER)
|
|
damg_thresh=40;
|
|
else
|
|
damg_thresh=random(15,25);
|
|
if(loser.health>damg_thresh)
|
|
damg=damg_thresh;
|
|
else
|
|
damg=1000;
|
|
self.count+=1;
|
|
if(self.count>=8)
|
|
self.count=0;
|
|
tospot=(loser.absmin+loser.absmax)*0.5;
|
|
zap_count+=1;
|
|
|
|
do_lightning2 (self,self.count,STREAM_ATTACHED,4,org,tospot,damg);
|
|
numTargs += 1; // ensure that there are fewer than 5 targets hit...
|
|
org=tospot;
|
|
if(lastloser==self)
|
|
firstloser=loser;
|
|
lastloser=loser;
|
|
}
|
|
}
|
|
loser=loser.chain;
|
|
}
|
|
|
|
if(!zap_count)
|
|
{
|
|
branch_fire(org);
|
|
|
|
traceline(org, org + v_forward * 128, TRUE, self);
|
|
|
|
WriteCoord(MSG_MULTICAST, org_x + v_forward_x * 128 * trace_fraction);
|
|
WriteCoord(MSG_MULTICAST, org_y + v_forward_y * 128 * trace_fraction);
|
|
WriteCoord(MSG_MULTICAST, org_z + v_forward_z * 128 * trace_fraction);
|
|
|
|
}
|
|
|
|
WriteCoord(MSG_MULTICAST, 0);
|
|
WriteCoord(MSG_MULTICAST, 0);
|
|
WriteCoord(MSG_MULTICAST, 0);
|
|
multicast(self.origin,MULTICAST_PVS);
|
|
}
|
|
|
|
|
|
void()lightning_ready_power;
|
|
void()lightning_ready_normal;
|
|
void lightning_fire_normal (void)
|
|
{
|
|
if(self.weaponframe_cnt)
|
|
self.wfs = advanceweaponframe($fidle1,$fidle16);
|
|
else
|
|
{
|
|
self.wfs = advanceweaponframe($normal1,$normal16);
|
|
if(self.weaponframe==$normal2)
|
|
{
|
|
if(self.effects&EF_DIMLIGHT)
|
|
self.lefty=TRUE;
|
|
else
|
|
self.effects(+)EF_DIMLIGHT;
|
|
}
|
|
else if(self.weaponframe==$normal16)
|
|
{
|
|
if(!self.lefty)
|
|
self.effects(-)EF_DIMLIGHT;
|
|
else
|
|
self.lefty=FALSE;
|
|
}
|
|
}
|
|
self.th_weapon=lightning_fire_normal;
|
|
self.last_attack=time;
|
|
if(self.artifact_active&ART_TOMEOFPOWER)
|
|
{
|
|
if(self.effects&EF_DIMLIGHT)
|
|
{
|
|
if(!self.lefty)
|
|
self.effects(-)EF_DIMLIGHT;
|
|
else
|
|
self.lefty=FALSE;
|
|
}
|
|
lightning_ready_power();
|
|
}
|
|
else if(self.greenmana<6||
|
|
self.bluemana<6||
|
|
(!self.button0&&self.weaponframe==$normal16)
|
|
)
|
|
{
|
|
if(self.effects&EF_DIMLIGHT)
|
|
{
|
|
if(!self.lefty)
|
|
self.effects(-)EF_DIMLIGHT;
|
|
else
|
|
self.lefty=FALSE;
|
|
}
|
|
lightning_ready_normal();
|
|
}
|
|
else if(self.weaponframe==$normal12 ||(self.weaponframe>=$fidle1 &&self.weaponframe<=$fidle16))
|
|
{
|
|
if(self.attack_finished<time)
|
|
{
|
|
self.weaponframe_cnt=FALSE;
|
|
FireLightningBall();
|
|
sound(self,CHAN_WEAPON,"succubus/firelbal.wav",1,ATTN_NORM);
|
|
self.bluemana-=6;
|
|
self.greenmana-=6;
|
|
self.attack_finished=time+1;
|
|
self.weaponframe=$normal13;
|
|
}
|
|
else
|
|
self.weaponframe_cnt=TRUE;
|
|
}
|
|
}
|
|
|
|
void lightning_fire_power (void)
|
|
{
|
|
self.wfs = advanceweaponframe($power1,$power16);
|
|
self.th_weapon=lightning_fire_power;
|
|
self.last_attack=time;
|
|
if(!self.artifact_active&ART_TOMEOFPOWER)
|
|
{
|
|
stopSound(self,CHAN_UPDATE);
|
|
self.effects(-)EF_UPDATESOUND;
|
|
self.t_width=SOUND_STOPPED;
|
|
lightning_ready_normal();
|
|
}
|
|
else if(self.greenmana<4||self.bluemana<4||!self.button0)
|
|
{
|
|
stopSound(self,CHAN_UPDATE);
|
|
self.effects(-)EF_UPDATESOUND;
|
|
self.t_width=SOUND_STOPPED;
|
|
lightning_ready_power();
|
|
}
|
|
else
|
|
{
|
|
if(self.t_width!=SOUND_STARTED)
|
|
{
|
|
sound(self,CHAN_UPDATE+PHS_OVERRIDE_R,"succubus/firelght.wav",1,ATTN_LOOP);
|
|
self.effects(+)EF_UPDATESOUND;
|
|
self.t_width=SOUND_STARTED;
|
|
}
|
|
if(!self.weaponframe_cnt)
|
|
shebitch_chain_lightning_strike();
|
|
self.weaponframe_cnt+=1;
|
|
if(self.weaponframe_cnt==4)
|
|
self.weaponframe_cnt=0;
|
|
}
|
|
}
|
|
|
|
void() Suc_Litn_Fire =
|
|
{
|
|
self.weaponframe_cnt=FALSE;
|
|
if(self.artifact_active&ART_TOMEOFPOWER)
|
|
lightning_fire_power();
|
|
else
|
|
lightning_fire_normal();
|
|
|
|
thinktime self : 0;
|
|
};
|
|
|
|
|
|
void lightning_ready_power (void)
|
|
{
|
|
if(random()<=0.07)
|
|
{
|
|
self.weaponframe=$pidle1 + rint(random(15));
|
|
sound(self,CHAN_WEAPON,"succubus/buzz.wav",1,ATTN_NORM);
|
|
self.effects(+)EF_MUZZLEFLASH;
|
|
}
|
|
else
|
|
self.weaponframe=$pidle1;
|
|
self.th_weapon=lightning_ready_power;
|
|
if(!self.artifact_active&ART_TOMEOFPOWER)
|
|
lightning_ready_normal();
|
|
}
|
|
|
|
void lightning_ready_flip (void)
|
|
{
|
|
self.wfs = advanceweaponframe($nidle1,$nidle16);
|
|
self.th_weapon=lightning_ready_flip;
|
|
if(self.wfs==WF_CYCLE_WRAPPED)
|
|
lightning_ready_normal();
|
|
}
|
|
|
|
void lightning_ready_normal (void)
|
|
{
|
|
self.weaponframe=$normal1;
|
|
self.th_weapon=lightning_ready_normal;
|
|
if(self.artifact_active&ART_TOMEOFPOWER)
|
|
lightning_ready_power();
|
|
else if(random(1000)<1)
|
|
{
|
|
sound (self, CHAN_WEAPON, "weapons/vorpswng.wav", 1, ATTN_NORM);
|
|
lightning_ready_flip();
|
|
}
|
|
}
|
|
|
|
void lightning_ready (void)
|
|
{
|
|
if(self.artifact_active&ART_TOMEOFPOWER)
|
|
lightning_ready_power();
|
|
else
|
|
lightning_ready_normal();
|
|
}
|
|
|
|
void lightning_select (void)
|
|
{
|
|
self.wfs = advanceweaponframe($select1,$select12);
|
|
self.weaponmodel = "models/sucwp4.mdl";
|
|
self.th_weapon=lightning_select;
|
|
if(self.wfs==WF_CYCLE_WRAPPED)
|
|
{
|
|
self.attack_finished = time - 1;
|
|
lightning_ready_flip();
|
|
}
|
|
}
|
|
|
|
void lightning_deselect (void)
|
|
{
|
|
self.wfs = advanceweaponframe($select12,$select1);
|
|
self.th_weapon=lightning_deselect;
|
|
if(self.wfs==WF_CYCLE_WRAPPED)
|
|
W_SetCurrentAmmo();
|
|
}
|
|
|
|
|