484 lines
12 KiB
C++
484 lines
12 KiB
C++
/*
|
|
* $Header: /HexenWorld/HCode/crossbow.hc 27 4/06/98 12:48p Ssengele $
|
|
*/
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
Q:\art\models\weapons\crossbow\final\crossbow.hc
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
// For building the model
|
|
$cd Q:\art\models\weapons\crossbow\final
|
|
$origin 0 0 0
|
|
$base base skin
|
|
$skin skin
|
|
$flags 0
|
|
|
|
//
|
|
$frame select1 select2 select3 select4 select5
|
|
$frame select6 select7 select8 select9 select10
|
|
$frame select11 select12 select13 select14 select15
|
|
|
|
//
|
|
$frame shoot1 shoot2 shoot3 shoot4 shoot5
|
|
$frame shoot6 shoot7 shoot8 shoot9 shoot10
|
|
$frame shoot11 shoot12 shoot13 shoot14 shoot15
|
|
$frame shoot16 shoot17 shoot18 shoot19
|
|
|
|
void AssBoltExplosion ()
|
|
{
|
|
T_RadiusDamage (self, self.owner, self.dmg, world);
|
|
|
|
remove (self);
|
|
}
|
|
|
|
void XbowBoltTurn(entity bolt)
|
|
{
|
|
vector dir;
|
|
|
|
bolt.xbo_teleported = 1;
|
|
bolt.takedamage=DAMAGE_NO;
|
|
// bolt.solid = SOLID_NOT;
|
|
bolt.xbo_startpos = bolt.origin;
|
|
dir = vectoangles(bolt.velocity);
|
|
updateeffect(bolt.xbo_effect_id, CE_HWXBOWSHOOT, bolt.boltnum*16+128, dir_x, dir_y, bolt.origin);
|
|
}
|
|
|
|
void() CB_BoltStick=
|
|
{
|
|
if(self.wait<=time)
|
|
self.think=AssBoltExplosion;
|
|
thinktime self : 0;
|
|
};
|
|
|
|
void CB_RemoveEffect (void)
|
|
{
|
|
endeffect(MSG_ALL,self.xbo_effect_id);
|
|
remove(self);
|
|
}
|
|
|
|
void CB_FinishBoltEffect (void)
|
|
{
|
|
entity finisher;
|
|
finisher = spawn();
|
|
finisher.think = CB_RemoveEffect;
|
|
finisher.xbo_effect_id = self.xbo_effect_id;
|
|
thinktime finisher : 5.0;
|
|
}
|
|
|
|
void CB_RemoveBoltFromList (void)
|
|
{
|
|
entity curbolt;
|
|
|
|
if (self.xbo_effect_id == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((self == self.firstbolt)&&(self.nextbolt == world))//i'm the last guy in the list--stop effect
|
|
{
|
|
CB_FinishBoltEffect();
|
|
self.xbo_effect_id = -1;
|
|
return;
|
|
}
|
|
|
|
if (self == self.firstbolt)//i'm the first in the list--let everyone know that the the new head of the list is the one after me
|
|
{
|
|
curbolt = self.nextbolt;
|
|
while (curbolt != world)
|
|
{
|
|
curbolt.firstbolt = self.nextbolt;
|
|
curbolt = curbolt.nextbolt;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curbolt = self.firstbolt;
|
|
while (curbolt.nextbolt != self)
|
|
{
|
|
curbolt = curbolt.nextbolt;
|
|
}
|
|
curbolt.nextbolt = self.nextbolt;
|
|
}
|
|
self.xbo_effect_id = -1;
|
|
}
|
|
|
|
void CB_HitEffect (vector v_forward)
|
|
{
|
|
vector stickspot;
|
|
float ttype;
|
|
|
|
stickspot = v_forward * 8;
|
|
|
|
//build the impact code byte now:
|
|
|
|
//lowest 4 bits of byte indicate thingtype--can't use THINGTYPE_ consts because there are too many
|
|
ttype = GetImpactType(other);
|
|
|
|
if (other.takedamage)//high bit of the byte indicates whether hit object takes damage
|
|
{
|
|
ttype += 128;
|
|
}
|
|
|
|
ttype += self.boltnum * 16;//2nd, 3rd, and 4th higshest bits in byte indicate bolt number
|
|
|
|
ttype += 1;//lowest bit set means that this bolt has hit
|
|
|
|
//done building impact code byte****
|
|
|
|
//now figure out how far i've travelled
|
|
|
|
stickspot = self.origin-self.xbo_startpos;
|
|
|
|
updateeffect(self.xbo_effect_id, CE_HWXBOWSHOOT, ttype, vlen(stickspot));
|
|
|
|
CB_RemoveBoltFromList();
|
|
}
|
|
|
|
void() CB_BoltHit=
|
|
{
|
|
if(other==self.owner||(other.owner==self.owner&&other.classname==self.classname))
|
|
return;
|
|
|
|
if (self.xbo_teleported)
|
|
return;
|
|
|
|
float stick;
|
|
|
|
v_forward=normalize(self.velocity);
|
|
setsize(self,'0 0 0','0 0 0');
|
|
self.takedamage=DAMAGE_NO;
|
|
self.velocity='0 0 0';
|
|
self.movetype=MOVETYPE_NOCLIP;
|
|
self.solid=SOLID_NOT;
|
|
self.touch=SUB_Null;
|
|
// self.health=other.health;
|
|
|
|
CB_HitEffect (v_forward);
|
|
|
|
if(other.takedamage)
|
|
{
|
|
if(self.classname=="bolt")
|
|
T_Damage(other,self,self.owner,15);
|
|
else
|
|
T_Damage(other,self,self.owner,3);
|
|
}
|
|
else
|
|
{
|
|
if(self.classname!="bolt")
|
|
stick=TRUE;
|
|
self.wait=time + self.fusetime;//random(1,3);
|
|
}
|
|
|
|
//FIXME: only stick in if thingtype is wood or flesh,
|
|
//otherwise, no damage and bounce off!
|
|
if(other.movetype||other.takedamage||stick||other.health)
|
|
{
|
|
if(stick)
|
|
{
|
|
self.enemy=other;
|
|
self.think=CB_BoltStick;
|
|
thinktime self : 0;
|
|
}
|
|
else if(self.classname=="bolt")
|
|
remove(self);
|
|
else
|
|
AssBoltExplosion();
|
|
}
|
|
else
|
|
{
|
|
self.movetype=MOVETYPE_NONE;
|
|
if(self.classname=="bolt")
|
|
self.think=SUB_Remove;
|
|
else
|
|
self.think=AssBoltExplosion;
|
|
thinktime self : 2;
|
|
}
|
|
};
|
|
|
|
void bolt_death (void)
|
|
{
|
|
vector stickspot;
|
|
float ttype;
|
|
|
|
stickspot = v_forward * 8;
|
|
|
|
//build the impact code byte now:
|
|
|
|
//lowest 4 bits of byte indicate thingtype--can't use THINGTYPE_ consts because there are too many
|
|
|
|
//high bit of the byte indicates whether hit object takes damage
|
|
|
|
ttype = self.boltnum * 16;//2nd, 3rd, and 4th higshest bits in byte indicate bolt number
|
|
|
|
ttype += 1;//lowest bit set means that this bolt has hit
|
|
|
|
//done building impact code byte****
|
|
|
|
//now figure out how far i've travelled
|
|
|
|
stickspot = self.origin-self.xbo_startpos;
|
|
|
|
updateeffect(self.xbo_effect_id, CE_HWXBOWSHOOT, ttype, vlen(stickspot));
|
|
|
|
CB_RemoveBoltFromList();
|
|
remove(self);
|
|
}
|
|
|
|
void fbolt_death (void)
|
|
{
|
|
vector stickspot;
|
|
float ttype;
|
|
|
|
self.takedamage=DAMAGE_NO;
|
|
self.th_die = SUB_Null;
|
|
|
|
stickspot = v_forward * 8;
|
|
|
|
//build the impact code byte now:
|
|
|
|
//lowest 4 bits of byte indicate thingtype--can't use THINGTYPE_ consts because there are too many
|
|
|
|
//high bit of the byte indicates whether hit object takes damage
|
|
|
|
ttype = self.boltnum * 16;//2nd, 3rd, and 4th higshest bits in byte indicate bolt number
|
|
|
|
ttype += 1;//lowest bit set means that this bolt has hit
|
|
|
|
//done building impact code byte****
|
|
|
|
//now figure out how far i've travelled
|
|
|
|
stickspot = self.origin-self.xbo_startpos;
|
|
|
|
updateeffect(self.xbo_effect_id, CE_HWXBOWSHOOT, ttype, vlen(stickspot));
|
|
|
|
CB_RemoveBoltFromList();
|
|
AssBoltExplosion();
|
|
}
|
|
|
|
void ArrowFlyThink (void)
|
|
{
|
|
if (self.xbo_teleported >0)
|
|
{
|
|
self.xbo_teleported = self.xbo_teleported - 1;
|
|
// self.solid = SOLID_BBOX;
|
|
// self.takedamage=DAMAGE_YES;
|
|
}
|
|
else
|
|
{
|
|
self.xbo_teleported = FALSE;
|
|
}
|
|
self.velocity = normalize(self.velocity)*self.speed;
|
|
if(self.lifetime<time&&self.mins=='0 0 0')
|
|
{
|
|
3;//or 4?...
|
|
// self.takedamage=DAMAGE_YES;
|
|
// setsize(self,'-3 -3 -2','3 3 2');
|
|
}
|
|
if(self.model=="models/flaming.mdl")
|
|
{
|
|
self.frame+=1;
|
|
if(self.frame>9)
|
|
self.frame=0;
|
|
}
|
|
// self.angles=vectoangles(self.velocity);
|
|
self.think=ArrowFlyThink;
|
|
thinktime self : 0.05;
|
|
}
|
|
void ArrowSound (void)
|
|
{
|
|
//attn_static instead?
|
|
// sound(self,CHAN_BODY,"assassin/arrowfly.wav",1,ATTN_NORM);
|
|
self.think=ArrowFlyThink;
|
|
thinktime self : 0;
|
|
}
|
|
|
|
void FlamingArrowThink (void)
|
|
{
|
|
ArrowSound();
|
|
}
|
|
|
|
void ArrowThinkEnt (entity who)//call me right away now
|
|
{
|
|
vector dir, oldvel;
|
|
oldvel = who.velocity;
|
|
dir=normalize(who.velocity);
|
|
traceline(who.origin,who.origin+dir*1000,FALSE,who);
|
|
if(!trace_ent.takedamage)
|
|
HomeThinkEnt(who);
|
|
|
|
who.angles=vectoangles(who.velocity);
|
|
|
|
if(who.classname=="bolt")
|
|
{
|
|
//only send new course if it's changed
|
|
if (oldvel_x != who.velocity_x || oldvel_y != who.velocity_y || oldvel_z != who.velocity_z)
|
|
{
|
|
dir = vectoangles(who.velocity);
|
|
updateeffect(who.xbo_effect_id, CE_HWXBOWSHOOT, who.boltnum*16, dir_x, dir_y);
|
|
}
|
|
who.think=ArrowSound;
|
|
}
|
|
else
|
|
{
|
|
//only send new course if it's changed
|
|
if (oldvel_x != who.velocity_x || oldvel_y != who.velocity_y || oldvel_z != who.velocity_z)
|
|
{
|
|
dir = vectoangles(who.velocity);
|
|
updateeffect(who.xbo_effect_id, CE_HWXBOWSHOOT, who.boltnum*16, dir_x, dir_y);
|
|
}
|
|
who.think=FlamingArrowThink;
|
|
}
|
|
}
|
|
|
|
entity (float offset, float powered_up, entity prevbolt, float boltnumber, float effectnum) FireCB_Bolt =
|
|
{
|
|
local entity missile;
|
|
makevectors(self.v_angle);
|
|
missile=spawn();
|
|
missile.xbo_teleported = FALSE;
|
|
missile.xbo_effect_id = effectnum;
|
|
missile.takedamage=DAMAGE_NO;
|
|
// bprint(PRINT_MEDIUM,ftos(missile.xbo_effect_id));
|
|
// bprint(PRINT_MEDIUM," effect has new bolt\n");
|
|
|
|
missile.owner=self;
|
|
missile.solid=SOLID_BBOX;
|
|
missile.hull=HULL_POINT;
|
|
missile.health=9999;//geesh, are we still getting stack overflows?!?!?! bolts shouldn't be taking damage, but if they still are for whatever reason, give them lotsa health.
|
|
|
|
// make sll of bolts in this effect
|
|
if (prevbolt == world)
|
|
{
|
|
missile.firstbolt = missile;
|
|
}
|
|
else
|
|
{
|
|
prevbolt.nextbolt = missile;
|
|
missile.firstbolt = prevbolt.firstbolt;
|
|
}
|
|
missile.nextbolt = world;
|
|
|
|
missile.boltnum = boltnumber;
|
|
|
|
|
|
// if(deathmatch)//i'm not finding a global like this available on client, so always decrease offset
|
|
offset*=.333;
|
|
if(powered_up)
|
|
{
|
|
missile.frags=TRUE;
|
|
missile.thingtype=THINGTYPE_METAL;
|
|
missile.movetype=MOVETYPE_FLYMISSILE;
|
|
missile.classname="flaming arrow";
|
|
// setmodel(missile,"models/flaming.mdl");
|
|
missile.dmg=40;
|
|
missile.drawflags(+)MLS_FIREFLICKER;
|
|
// missile.th_die=fbolt_death;
|
|
}
|
|
else
|
|
{
|
|
missile.thingtype=THINGTYPE_WOOD;
|
|
missile.movetype=MOVETYPE_FLYMISSILE;
|
|
//bounce testing
|
|
// missile.movetype=MOVETYPE_BOUNCEMISSILE;
|
|
missile.classname="bolt";
|
|
// setmodel(missile,"models/arrow.mdl");
|
|
// missile.th_die=bolt_death;
|
|
}
|
|
missile.touch=CB_BoltHit;
|
|
|
|
// missile.speed=random(700,1200);
|
|
missile.speed = 800.0 + seedrand()*500.0;
|
|
missile.fusetime = 1.0 + seedrand()*2.0;
|
|
|
|
missile.o_angle=missile.velocity=normalize(v_forward)*missile.speed+v_right*offset;
|
|
missile.angles=vectoangles(missile.velocity);
|
|
|
|
missile.ideal_yaw=TRUE;
|
|
missile.turn_time = 0;
|
|
missile.veer=0;
|
|
|
|
missile.lifetime=time+0.2;
|
|
|
|
setsize(missile,'0 0 0','0 0 0');
|
|
setorigin(missile,self.origin+self.proj_ofs+v_forward*8+v_right*offset*0.05);
|
|
|
|
missile.xbo_startpos = missile.origin;//save start pos so i can send the total distance i travelled when i finish
|
|
|
|
ArrowThinkEnt(missile);
|
|
thinktime missile : 0;
|
|
|
|
return (missile);
|
|
};
|
|
|
|
|
|
void()crossbow_fire;
|
|
void crossbow_idle(void)
|
|
{
|
|
self.th_weapon=crossbow_idle;
|
|
self.weaponframe=$shoot19;
|
|
}
|
|
|
|
void crossbow_fire (void)
|
|
{
|
|
entity curmissile;
|
|
float bolteffect,randseed;
|
|
|
|
makevectors(self.v_angle);
|
|
self.wfs = advanceweaponframe($shoot1,$shoot18);
|
|
self.th_weapon=crossbow_fire;
|
|
if (self.weaponframe == $shoot2)
|
|
if(self.artifact_active&ART_TOMEOFPOWER)
|
|
{
|
|
randseed = random(255);
|
|
setseed(randseed);
|
|
bolteffect = starteffect(CE_HWXBOWSHOOT, self.origin+self.proj_ofs+v_forward*8, self.v_angle, 5, randseed);
|
|
curmissile=FireCB_Bolt(-200.0,TRUE,world,0,bolteffect);
|
|
curmissile=FireCB_Bolt(-100.0,TRUE,curmissile,1,bolteffect);
|
|
curmissile=FireCB_Bolt(0,TRUE,curmissile,2,bolteffect);
|
|
curmissile=FireCB_Bolt(100.0,TRUE,curmissile,3,bolteffect);
|
|
curmissile=FireCB_Bolt(200.0,TRUE,curmissile,4,bolteffect);
|
|
self.attack_finished=time+0.3;
|
|
self.bluemana-=10;
|
|
}
|
|
else
|
|
{
|
|
randseed = random(255);
|
|
setseed(randseed);
|
|
bolteffect = starteffect(CE_HWXBOWSHOOT, self.origin+self.proj_ofs+v_forward*8, self.v_angle, 3, randseed);
|
|
curmissile=FireCB_Bolt(-100.0,FALSE,world,0,bolteffect);
|
|
curmissile=FireCB_Bolt(0,FALSE,curmissile,1,bolteffect);
|
|
curmissile=FireCB_Bolt(100.0,FALSE,curmissile,2,bolteffect);
|
|
self.attack_finished=time+0.5;
|
|
self.bluemana-=3;
|
|
}
|
|
else if (self.wfs==WF_CYCLE_WRAPPED)
|
|
crossbow_idle();
|
|
}
|
|
|
|
void crossbow_select (void)
|
|
{
|
|
//selection sound?
|
|
self.wfs = advanceweaponframe($select15,$select1);
|
|
self.weaponmodel = "models/crossbow.mdl";
|
|
self.th_weapon=crossbow_select;
|
|
if (self.weaponframe==$select1)
|
|
{
|
|
self.attack_finished = time - 1;
|
|
crossbow_idle();
|
|
}
|
|
}
|
|
|
|
void crossbow_deselect (void)
|
|
{
|
|
self.wfs = advanceweaponframe($select1,$select15);
|
|
self.th_weapon=crossbow_deselect;
|
|
if (self.wfs==WF_CYCLE_WRAPPED)
|
|
W_SetCurrentAmmo();
|
|
}
|
|
|