1135 lines
32 KiB
C
1135 lines
32 KiB
C
// -------------------------------------------------------
|
|
// Special Weapon code (Deathmatch only)
|
|
//
|
|
// The main procedure is at the end, this is called every
|
|
// frame during a special attack.
|
|
// -------------------------------------------------------
|
|
|
|
void() SpecialWeaponChange =
|
|
{
|
|
if (self.character == CHAR_WOLVERINE) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Claw Attack selected.\n");
|
|
else
|
|
sprint(self, "Jump Attack selected.\n");
|
|
}
|
|
else if (self.character == CHAR_STORM) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Wind Attack selected.\n");
|
|
else
|
|
sprint(self, "Lightning Attack selected.\n");
|
|
}
|
|
else if (self.character == CHAR_CYCLOPS) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Fast Laser selected.\n");
|
|
else
|
|
sprint(self, "Mega-Laser selected.\n");
|
|
}
|
|
else if (self.character == CHAR_PSYLOCKE) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Sword Attack selected.\n");
|
|
else
|
|
sprint(self, "Psychic Paralyze selected.\n");
|
|
}
|
|
else if (self.character == CHAR_ANGEL) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Dart Spray selected.\n");
|
|
else
|
|
sprint(self, "Wing Defense selected.\n");
|
|
}
|
|
else if (self.character == CHAR_BEAST) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Triple Punch selected.\n");
|
|
else
|
|
sprint(self, "Floor Pound selected.\n");
|
|
}
|
|
else if (self.character == CHAR_GAMBIT) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Staff Attack selected.\n");
|
|
else
|
|
sprint(self, "Throwing Cards selected.\n");
|
|
}
|
|
else if (self.character == CHAR_ICEMAN) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Shard Attack selected.\n");
|
|
else
|
|
sprint(self, "Freeze Blast selected.\n");
|
|
}
|
|
else if (self.character == CHAR_BISHOP) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Gun Attack selected.\n");
|
|
else
|
|
sprint(self, "Energy Blast selected.\n");
|
|
}
|
|
else if (self.character == CHAR_ROGUE) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Single Punch selected.\n");
|
|
else
|
|
sprint(self, "Super Punch selected.\n");
|
|
}
|
|
else if (self.character == CHAR_CANNONBALL) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Punch Attack selected.\n");
|
|
else
|
|
sprint(self, "Flying Punch selected.\n");
|
|
}
|
|
else if (self.character == CHAR_PHOENIX) {
|
|
if (!self.special_weapon)
|
|
sprint(self, "Tractor Beam selected.\n");
|
|
else
|
|
sprint(self, "Homing Blast selected.\n");
|
|
}
|
|
};
|
|
|
|
void(float side) Wolvy_Melee =
|
|
{
|
|
local entity other;
|
|
|
|
makevectors (self.angles);
|
|
traceline(self.origin, self.origin + v_forward * 48, FALSE, self);
|
|
|
|
if ((trace_ent != world) && (trace_ent.takedamage != DAMAGE_NO))
|
|
other = trace_ent;
|
|
else
|
|
return;
|
|
|
|
sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM);
|
|
T_Damage (other, self, self, 15);
|
|
|
|
SpawnMeatSpray (self.origin + v_forward*16, side * v_right);
|
|
};
|
|
|
|
|
|
void() Wolvy_JumpThink =
|
|
{
|
|
local float ldmg;
|
|
local vector dir;
|
|
|
|
if (self.health <= 0)
|
|
return;
|
|
|
|
// check for enemy getting hit
|
|
makevectors(self.v_angle);
|
|
dir = v_forward;
|
|
traceline(self.origin, self.origin + dir * 128, FALSE, self);
|
|
if ((trace_ent != world) && (trace_ent.takedamage != DAMAGE_NO))
|
|
{
|
|
ldmg = 8 + 5*random();
|
|
T_Damage (trace_ent, self, self, ldmg);
|
|
trace_ent.punchangle_x = -10;
|
|
|
|
sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM);
|
|
}
|
|
};
|
|
|
|
void() Wolvy_Jump =
|
|
{
|
|
if (!(self.flags & FL_ONGROUND))
|
|
return;
|
|
|
|
makevectors (self.v_angle);
|
|
|
|
self.origin_z = self.origin_z + 1;
|
|
self.velocity = v_forward * 700 + '0 0 210';
|
|
if (self.velocity_z > 350)
|
|
self.velocity_z = 350;
|
|
|
|
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
|
|
|
|
if (self.flags & FL_ONGROUND)
|
|
self.flags = self.flags - FL_ONGROUND;
|
|
};
|
|
|
|
void() Storm_Lightning =
|
|
{
|
|
local vector dir;
|
|
|
|
self.effects = self.effects | EF_MUZZLEFLASH;
|
|
|
|
makevectors(self.v_angle);
|
|
dir = v_forward;
|
|
|
|
traceline (self.origin + '0 0 16', self.origin + dir*600 + '0 0 16', TRUE, self);
|
|
|
|
msg_entity = self;
|
|
|
|
WriteByte (MSG_ONE, SVC_TEMPENTITY);
|
|
WriteByte (MSG_ONE, TE_LIGHTNING1);
|
|
WriteEntity (MSG_ONE, self);
|
|
WriteCoord (MSG_ONE, self.origin_x);
|
|
WriteCoord (MSG_ONE, self.origin_y);
|
|
WriteCoord (MSG_ONE, self.origin_z + 8);
|
|
WriteCoord (MSG_ONE, trace_endpos_x);
|
|
WriteCoord (MSG_ONE, trace_endpos_y);
|
|
WriteCoord (MSG_ONE, trace_endpos_z);
|
|
|
|
// show lightning differently for others
|
|
|
|
msg_entity = find(msg_entity, classname, "player");
|
|
if (msg_entity == world)
|
|
msg_entity = find(msg_entity, classname, "player");
|
|
|
|
while (msg_entity != self) {
|
|
WriteByte (MSG_ONE, SVC_TEMPENTITY);
|
|
WriteByte (MSG_ONE, TE_LIGHTNING1);
|
|
WriteEntity (MSG_ONE, self);
|
|
WriteCoord (MSG_ONE, self.origin_x);
|
|
WriteCoord (MSG_ONE, self.origin_y);
|
|
WriteCoord (MSG_ONE, self.origin_z + 20);
|
|
WriteCoord (MSG_ONE, trace_endpos_x);
|
|
WriteCoord (MSG_ONE, trace_endpos_y);
|
|
WriteCoord (MSG_ONE, trace_endpos_z);
|
|
|
|
msg_entity = find(msg_entity, classname, "player");
|
|
if (msg_entity == world)
|
|
msg_entity = find(msg_entity, classname, "player");
|
|
}
|
|
|
|
|
|
LightningDamage (self.origin + '0 0 16', trace_endpos, self, 15);
|
|
};
|
|
|
|
void() Storm_Wind =
|
|
{
|
|
local entity trav;
|
|
local float strength, dist;
|
|
local vector vect, vect_angle;
|
|
|
|
sound (self, CHAN_WEAPON, "storm/w_attack.wav", 1, ATTN_NORM);
|
|
|
|
trav = findradius(self.origin, 256);
|
|
while (trav != world) {
|
|
|
|
// check that the object is damage-able and is infront of self
|
|
vect = normalize(trav.origin - self.origin);
|
|
vect_angle = vectoangles(vect);
|
|
|
|
if ((trav != self) &&
|
|
((trav.takedamage) && (trav.movetype)) &&
|
|
(fabs( angle_diff( vect_angle_y, self.angles_y)) < 35)) { // give em some wind
|
|
|
|
strength = 200;
|
|
dist = vlen(trav.origin - self.origin);
|
|
if (dist > 128) { // reduce strength of blast
|
|
strength = ((dist - 128) / 128) * strength;
|
|
}
|
|
|
|
// blast now
|
|
trav.flags = trav.flags - (trav.flags & FL_ONGROUND);
|
|
trav.velocity = (trav.velocity * 0.5) + (vect * 600);
|
|
trav.velocity_z = 300;
|
|
|
|
trav.angles = trav.v_angle = self.angles;
|
|
trav.punchangle_x = -20;
|
|
trav.fixangle = TRUE;
|
|
|
|
}
|
|
|
|
trav = trav.chain;
|
|
}
|
|
|
|
self.last_wind = time;
|
|
};
|
|
|
|
void() LaserTouch;
|
|
void() DM_Cyclops_Fast_Laser =
|
|
{
|
|
local entity missile;
|
|
local vector vect;
|
|
|
|
self.effects = self.effects | EF_MUZZLEFLASH;
|
|
stuffcmd(self, "rf\n"); // flash screen red
|
|
|
|
sound (self, CHAN_VOICE, "items/inv1.wav", 1, ATTN_NORM);
|
|
|
|
missile = spawn ();
|
|
missile.owner = self;
|
|
missile.movetype = MOVETYPE_BOUNCE;
|
|
missile.solid = SOLID_BBOX;
|
|
missile.classname = "laser";
|
|
|
|
makevectors(self.v_angle);
|
|
missile.velocity = v_forward * 1700;
|
|
|
|
missile.angles = vectoangles(missile.velocity);
|
|
missile.old_velocity = missile.velocity;
|
|
|
|
missile.touch = LaserTouch;
|
|
|
|
missile.last_touch = 0;
|
|
missile.oldorigin = missile.origin;
|
|
missile.nextthink = time + 2;
|
|
missile.think = SUB_Remove;
|
|
|
|
setmodel (missile, "progs/claser1.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
setorigin (missile, self.origin + v_forward * 16 + '0 0 22');
|
|
};
|
|
|
|
void() DM_Big_Laser_Touch =
|
|
{
|
|
if (other == self.owner)
|
|
return;
|
|
|
|
if (other.takedamage == DAMAGE_AIM)
|
|
{
|
|
spawn_touchblood (20);
|
|
T_Damage(other, self, self.owner, 30);
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
self.last_touch = time;
|
|
|
|
sound (self, CHAN_WEAPON, "doors/airdoor2.wav", 1, ATTN_NORM);
|
|
if (self.velocity == '0 0 0')
|
|
remove(self);
|
|
|
|
};
|
|
|
|
void() DM_Cyclops_Big_Laser =
|
|
{
|
|
local entity missile;
|
|
local vector vect;
|
|
|
|
self.effects = self.effects | EF_MUZZLEFLASH;
|
|
stuffcmd(self, "rf\n"); // flash screen red
|
|
|
|
sound (self, CHAN_VOICE, "items/inv1.wav", 1, ATTN_NORM);
|
|
|
|
missile = spawn ();
|
|
missile.owner = self;
|
|
missile.movetype = MOVETYPE_BOUNCE;
|
|
missile.solid = SOLID_BBOX;
|
|
missile.classname = "laser";
|
|
|
|
makevectors(self.v_angle);
|
|
missile.velocity = v_forward * 1200;
|
|
|
|
missile.angles = vectoangles(missile.velocity);
|
|
missile.old_velocity = missile.velocity;
|
|
|
|
missile.touch = DM_Big_Laser_Touch;
|
|
|
|
missile.last_touch = 0;
|
|
missile.oldorigin = missile.origin;
|
|
missile.nextthink = time + 2;
|
|
missile.think = SUB_Remove;
|
|
|
|
setmodel (missile, "progs/claser1.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
setorigin (missile, self.origin + v_forward * 16 + '0 0 22');
|
|
};
|
|
|
|
void() DM_Psylocke_Sword =
|
|
{
|
|
local entity plyr;
|
|
local vector delta;
|
|
local float ldmg;
|
|
|
|
makevectors(self.v_angle);
|
|
traceline(self.origin, self.origin + v_forward*55, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM)
|
|
plyr = trace_ent;
|
|
else
|
|
return;
|
|
|
|
// if ((plyr = FindSightEnemy(self.origin, v_forward, 60, 40, "player", self)) == world)
|
|
// return;
|
|
/*
|
|
delta = plyr.origin - self.origin;
|
|
|
|
if (vlen(delta) > 70)
|
|
return;
|
|
*/
|
|
ldmg = 15 + random() * 5;
|
|
T_Damage (plyr, self, self, ldmg);
|
|
};
|
|
|
|
|
|
void() DM_Psylocke_Parallize =
|
|
{
|
|
makevectors(self.v_angle);
|
|
traceline(self.origin, self.origin + v_forward*48, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM)
|
|
{
|
|
// got 'em
|
|
sound(self, CHAN_WEAPON, "player/what_1.wav", 1, ATTN_NORM);
|
|
|
|
trace_ent.parallize_time = time + 3;
|
|
trace_ent.x_flags = trace_ent.x_flags | X_PARALLIZED;
|
|
trace_ent.parallized_velocity = '0 0 0';
|
|
centerprint(trace_ent, "You have been paralyzed");
|
|
stuffcmd(trace_ent, "pl\n");
|
|
}
|
|
};
|
|
|
|
void(float heading_ofs) DM_AngelFeather =
|
|
{
|
|
local vector newangle, targ_vect;
|
|
local entity missile;
|
|
|
|
newangle = self.v_angle;
|
|
newangle_y = anglemod(newangle_y + heading_ofs);
|
|
|
|
newangle_x = newangle_x + (random() * 10) - 5;
|
|
|
|
makevectors(newangle);
|
|
|
|
launch_spike (self.origin + '0 0 16' + v_forward*14, v_forward);
|
|
newmis.classname = "angel_dart";
|
|
setmodel (newmis, "progs/dart.mdl");
|
|
setsize(newmis, '0 0 0', '0 0 0');
|
|
};
|
|
|
|
void() DM_BeastPunch =
|
|
{
|
|
local vector delta;
|
|
local float ldmg;
|
|
local entity plyr;
|
|
|
|
makevectors(self.v_angle);
|
|
traceline(self.origin, self.origin + v_forward*55, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM)
|
|
plyr = trace_ent;
|
|
else
|
|
return;
|
|
|
|
ldmg = 9 + random() * 3;
|
|
T_Damage (plyr, self, self, ldmg);
|
|
|
|
if (random() < 0.5)
|
|
sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM);
|
|
else
|
|
sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM);
|
|
};
|
|
|
|
void() BeastPowTouch;
|
|
void() BeastPowThink;
|
|
void() DM_BeastPound =
|
|
{
|
|
local entity trav, plyr;
|
|
local entity missile;
|
|
local vector vec;
|
|
|
|
missile = spawn();
|
|
missile.classname = "beast_power";
|
|
missile.owner = self;
|
|
missile.solid = SOLID_TRIGGER;
|
|
missile.movetype = MOVETYPE_FLY;
|
|
|
|
setsize(missile, '0 0 0', '0 0 0');
|
|
setmodel(missile, "progs/pow.mdl");
|
|
|
|
makevectors(self.angles);
|
|
|
|
if ((plyr = FindSightEnemy(self.origin, v_forward, 256, 20, "player", self)) != world)
|
|
missile.velocity = normalize(plyr.origin - self.origin + plyr.velocity * 0.5) * 750;
|
|
else {
|
|
missile.velocity = v_forward * 750;
|
|
}
|
|
missile.velocity_z = 0;
|
|
|
|
setorigin(missile, self.origin + v_forward * 16);
|
|
|
|
vec = missile.velocity;
|
|
traceline(missile.origin + vec*frametime*2 + '0 0 32', missile.origin + vec*frametime*2 - '0 0 48', TRUE, world);
|
|
if (trace_fraction <= 1) {
|
|
missile.velocity = normalize(trace_endpos + '0 0 24' - missile.origin) * 750;
|
|
|
|
traceline(missile.origin + '0 0 32', missile.origin - '0 0 48', TRUE, world);
|
|
setorigin(missile, trace_endpos + '0 0 24');
|
|
}
|
|
|
|
missile.touch = BeastPowTouch;
|
|
missile.think = BeastPowThink;
|
|
missile.nextthink = time + 0.05;
|
|
missile.spawn_time = time;
|
|
|
|
sound (self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM);
|
|
sound (self, CHAN_WEAPON, "doors/stndr1.wav", 1, ATTN_NORM);
|
|
|
|
// send players airbourne
|
|
trav = find(world, classname, "player");
|
|
while (trav != world) {
|
|
if ((trav.flags & FL_ONGROUND) && (vlen(trav.origin - self.origin) < 256))
|
|
trav.velocity_z = 200;
|
|
|
|
trav = find(trav, classname, "player");
|
|
}
|
|
};
|
|
|
|
void() DM_Gambit_Strike =
|
|
{
|
|
local entity plyr;
|
|
local vector vect;
|
|
local float damg;
|
|
|
|
makevectors(self.v_angle);
|
|
traceline(self.origin, self.origin + v_forward*55, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM)
|
|
plyr = trace_ent;
|
|
else
|
|
return;
|
|
|
|
damg = 20 + random() * 5;
|
|
T_Damage (plyr, self, self, damg);
|
|
};
|
|
|
|
void(float heading_ofs, float zofs) DM_GambitCard =
|
|
{
|
|
local vector newangle, targ_vect, ofs;
|
|
local entity missile;
|
|
|
|
makevectors(self.v_angle);
|
|
targ_vect = v_forward;
|
|
newangle = vectoangles(targ_vect);
|
|
newangle_x = -1 * newangle_x;
|
|
newangle_y = anglemod(newangle_y + heading_ofs);
|
|
|
|
makevectors(newangle);
|
|
|
|
ofs = '0 0 0';
|
|
ofs_z = zofs;
|
|
launch_spike (self.origin + ofs + v_forward*14, v_forward);
|
|
newmis.classname = "gambit_card";
|
|
setmodel (newmis, "progs/card.mdl");
|
|
setsize(newmis, '0 0 0', '0 0 0');
|
|
};
|
|
|
|
void(vector org, vector dir) spawn_shard;
|
|
void(float offs) DM_Iceman_Shard =
|
|
{
|
|
local vector org, vect, ang;
|
|
|
|
ang = self.v_angle;
|
|
ang_y = anglemod(ang_y + offs);
|
|
|
|
makevectors (ang);
|
|
vect = v_forward;
|
|
|
|
org = self.origin + '0 0 12';
|
|
|
|
spawn_shard(org, vect);
|
|
};
|
|
|
|
void(vector org, vector dir) spawn_iceball;
|
|
void() DM_Iceman_Iceball =
|
|
{
|
|
local vector org,o2;
|
|
|
|
makevectors (self.v_angle);
|
|
|
|
org = self.origin + v_forward * 12 + '0 0 16';
|
|
|
|
spawn_iceball(org, v_forward);
|
|
};
|
|
|
|
|
|
void(float r_ofs) DM_Bishop_Shoot =
|
|
{
|
|
local vector vect;
|
|
local entity missile;
|
|
|
|
self.effects = self.effects | EF_MUZZLEFLASH;
|
|
|
|
makevectors(self.v_angle);
|
|
|
|
sound (self, CHAN_WEAPON, "doors/airdoor2.wav", 1, ATTN_NORM);
|
|
|
|
launch_spike (self.origin + '0 0 10' + v_forward*14 + v_right * r_ofs, v_forward);
|
|
newmis.dmg = 15 + random() * 5;
|
|
newmis.classname = "bishop_laser";
|
|
newmis.velocity = v_forward * 2000;
|
|
setmodel (newmis, "progs/laser.mdl");
|
|
setsize(newmis, '0 0 0', '0 0 0');
|
|
};
|
|
|
|
void() BishopSpecialTouch;
|
|
void() DM_Bishop_Special =
|
|
{
|
|
local vector vect;
|
|
local entity missile;
|
|
|
|
self.effects = self.effects | EF_MUZZLEFLASH;
|
|
|
|
sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM);
|
|
|
|
makevectors(self.v_angle);
|
|
|
|
vect = v_forward;
|
|
|
|
launch_spike (self.origin + '0 0 12' + v_forward*14, vect);
|
|
newmis.velocity = newmis.velocity * 0.75;
|
|
newmis.classname = "bishop_special";
|
|
newmis.touch = BishopSpecialTouch;
|
|
newmis.avelocity_z = 300;
|
|
setmodel (newmis, "progs/bisblast.mdl");
|
|
setsize(newmis, '0 0 0', '0 0 0');
|
|
};
|
|
|
|
void(float damage) DM_Rogue_Punch =
|
|
{
|
|
local entity plyr;
|
|
local float damg;
|
|
|
|
makevectors(self.v_angle);
|
|
traceline(self.origin, self.origin + v_forward*55, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM)
|
|
plyr = trace_ent;
|
|
else
|
|
return;
|
|
|
|
// hurt enemy
|
|
T_Damage(plyr, self, self, damage);
|
|
|
|
sound(self, CHAN_WEAPON, "zombie/z_hit.wav", 1, ATTN_NORM);
|
|
};
|
|
|
|
void() DM_Rogue_Fly =
|
|
{
|
|
local float vspeed, maxspeed;
|
|
|
|
makevectors(self.v_angle);
|
|
|
|
vspeed = vlen(self.velocity);
|
|
maxspeed = cvar("sv_maxspeed");
|
|
|
|
if (vspeed < maxspeed) {
|
|
self.velocity = self.old_velocity + v_forward * 2000 * frametime;
|
|
if (vlen(self.velocity) > (maxspeed + 100))
|
|
self.velocity = normalize(self.velocity) * (maxspeed + 50);
|
|
}
|
|
else {
|
|
self.velocity = v_forward * (maxspeed + 50);
|
|
}
|
|
|
|
self.old_velocity = self.velocity;
|
|
|
|
// check for punch
|
|
traceline(self.origin + '0 0 24', self.origin + '0 0 24' + v_forward*64, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM) {
|
|
T_Damage(trace_ent, self, self, 40 + random()*8);
|
|
sound(self, CHAN_WEAPON, "zombie/z_hit.wav", 1, ATTN_NORM);
|
|
}
|
|
};
|
|
|
|
void(float damage) DM_Cannon_Punch =
|
|
{
|
|
local entity plyr;
|
|
local float damg;
|
|
|
|
sound (self, CHAN_ITEM, "generic/swing1.wav", 1, ATTN_NORM);
|
|
|
|
makevectors(self.v_angle);
|
|
traceline(self.origin, self.origin + v_forward*55, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM)
|
|
plyr = trace_ent;
|
|
else
|
|
return;
|
|
|
|
// hurt enemy
|
|
T_Damage(plyr, self, self, damage);
|
|
|
|
if (random() < 0.5)
|
|
sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM);
|
|
else
|
|
sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM);
|
|
};
|
|
|
|
void() DM_Cannon_Fly =
|
|
{
|
|
local float vspeed, maxspeed;
|
|
|
|
makevectors(self.v_angle);
|
|
|
|
vspeed = vlen(self.velocity);
|
|
maxspeed = cvar("sv_maxspeed");
|
|
|
|
if (vspeed < maxspeed) {
|
|
self.velocity = self.old_velocity + v_forward * 2000 * frametime;
|
|
if (vlen(self.velocity) > (maxspeed + 100))
|
|
self.velocity = normalize(self.velocity) * (maxspeed + 150);
|
|
}
|
|
else {
|
|
self.velocity = v_forward * (maxspeed + 150);
|
|
}
|
|
|
|
if (self.last_flame_sound < (time - 0.75)) {
|
|
if (self.last_weapon_channel != CHAN_ITEM) {
|
|
sound (self, CHAN_ITEM, "cannon/flyloop.wav", 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_ITEM;
|
|
} else {
|
|
sound (self, CHAN_VOICE, "cannon/flyloop.wav", 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_VOICE;
|
|
}
|
|
|
|
self.last_flame_sound = time;
|
|
}
|
|
|
|
self.old_velocity = self.velocity;
|
|
|
|
// check for punch
|
|
traceline(self.origin + '0 0 24', self.origin + '0 0 24' + v_forward*64, FALSE, self);
|
|
|
|
if (trace_ent.takedamage == DAMAGE_AIM) {
|
|
T_Damage(trace_ent, self, self, 40 + random()*8);
|
|
sound (self, CHAN_BODY, "generic/swing1.wav", 1, ATTN_NORM);
|
|
|
|
if (random() < 0.5)
|
|
sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM);
|
|
else
|
|
sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM);
|
|
}
|
|
|
|
if (trace_fraction < 1) {
|
|
self.weaponframe = 14; // abort fly
|
|
}
|
|
};
|
|
|
|
|
|
void() BeamPlayerTouch =
|
|
{
|
|
local float vspeed, damg;
|
|
|
|
if (self.last_wall_hit > (time - 1))
|
|
return;
|
|
|
|
if (other != world)
|
|
return;
|
|
|
|
if (self.enemy.enemy != self) {
|
|
self.enemy = world;
|
|
self.touch = SUB_Null;
|
|
return;
|
|
}
|
|
|
|
vspeed = vlen(self.velocity);
|
|
|
|
if (vspeed < 100)
|
|
return;
|
|
|
|
// make sure player is travelling somewhat sideways
|
|
if (fabs(self.velocity_z) > 40)
|
|
return;
|
|
|
|
// find out which wall was likely to have been hit
|
|
traceline(self.origin, self.origin + self.velocity * 2, TRUE, self);
|
|
if (trace_fraction == 1)
|
|
return;
|
|
|
|
if (fabs(trace_plane_normal_z) > 0.3)
|
|
return;
|
|
|
|
//bprint(ftos(vspeed));
|
|
//bprint("\n");
|
|
|
|
damg = vspeed / 200;
|
|
if (damg > 25)
|
|
damg = 25;
|
|
|
|
// wall damage
|
|
T_Damage(self, self.enemy, self.enemy, damg);
|
|
self.last_wall_hit = time;
|
|
};
|
|
|
|
void() DM_TractorThink =
|
|
{
|
|
local vector ideal_pos;
|
|
|
|
makevectors(self.owner.v_angle);
|
|
|
|
ideal_pos = self.owner.origin + v_forward * self.owner.tractor_dist;
|
|
|
|
if (vlen(ideal_pos - self.owner.enemy.origin) > 8)
|
|
self.owner.enemy.velocity = self.owner.enemy.tractor_vel = (ideal_pos - self.owner.enemy.origin) * 4;
|
|
else
|
|
self.owner.enemy.velocity = self.owner.enemy.tractor_vel = '0 0 0';
|
|
|
|
self.owner.enemy.flags = self.owner.enemy.flags - (self.owner.enemy.flags & FL_ONGROUND);
|
|
|
|
self.nextthink = time + 0.05;
|
|
};
|
|
|
|
void() TractorParticleThink;
|
|
void() DM_PhoenixStartBeam =
|
|
{
|
|
// if player is already in a beam, abort attack
|
|
if ((self.enemy.x_flags & X_TRACTOR_BEAM_HOLD) && (self.enemy.flags & FL_GODMODE)) {
|
|
self.enemy = world;
|
|
return;
|
|
}
|
|
|
|
sound(self.enemy, CHAN_WEAPON, "items/damage3.wav", 1, ATTN_NORM);
|
|
|
|
self.flags = self.flags | FL_GODMODE;
|
|
self.last_special = time;
|
|
self.start_attack_health = self.health;
|
|
|
|
self.tractor_dist = vlen(self.enemy.origin - self.origin);
|
|
|
|
self.enemy.enemy = self;
|
|
self.enemy.touch = BeamPlayerTouch;
|
|
|
|
self.enemy.x_flags = self.enemy.x_flags | X_TRACTOR_BEAM_HOLD;
|
|
self.enemy.velocity = self.enemy.tractor_vel = '0 0 100';
|
|
setorigin(self.enemy, self.enemy.origin + '0 0 1');
|
|
self.enemy.flags = self.enemy.flags - (self.enemy.flags & FL_ONGROUND);
|
|
|
|
self.start_tractor_time = time;
|
|
self.enemy.start_tractor_time = time;
|
|
|
|
self.move_ent = spawn();
|
|
self.move_ent.owner = self;
|
|
|
|
self = self.move_ent;
|
|
|
|
self.flame_ent1 = spawn();
|
|
self.flame_ent2 = spawn();
|
|
self.flame_ent3 = spawn();
|
|
|
|
setmodel(self.flame_ent1, "progs/beampart.mdl");
|
|
setmodel(self.flame_ent2, "progs/beampart.mdl");
|
|
setmodel(self.flame_ent3, "progs/beampart.mdl");
|
|
|
|
setorigin(self.flame_ent1, self.origin);
|
|
setorigin(self.flame_ent2, self.origin);
|
|
setorigin(self.flame_ent3, self.origin);
|
|
|
|
self.flame_ent1.nextthink = time + 0.05;
|
|
self.flame_ent2.nextthink = time + 0.05;
|
|
self.flame_ent3.nextthink = time + 0.05;
|
|
|
|
// speed to travel
|
|
self.flame_ent1.speed = 800;
|
|
self.flame_ent2.speed = 400;
|
|
self.flame_ent3.speed = 200;
|
|
|
|
// distance from Phoenix
|
|
self.flame_ent1.t_length = 0;
|
|
self.flame_ent2.t_length = 0;
|
|
self.flame_ent3.t_length = 0;
|
|
|
|
// distance from center of tractor beam
|
|
self.flame_ent1.z_ofs = 10;
|
|
self.flame_ent2.z_ofs = 5;
|
|
self.flame_ent3.z_ofs = 0;
|
|
|
|
// 1 = travelling away from center, -1 = travelling towards center
|
|
self.flame_ent1.z_ofs_vel = -2;
|
|
self.flame_ent2.z_ofs_vel = 2.5;
|
|
self.flame_ent3.z_ofs_vel = 1;
|
|
|
|
self.flame_ent1.think = TractorParticleThink;
|
|
self.flame_ent2.think = TractorParticleThink;
|
|
self.flame_ent3.think = TractorParticleThink;
|
|
|
|
self.flame_ent1.owner = self.owner;
|
|
self.flame_ent2.owner = self.owner;
|
|
self.flame_ent3.owner = self.owner;
|
|
|
|
self.think = DM_TractorThink;
|
|
self.nextthink = time + 0.05;
|
|
|
|
self = self.owner;
|
|
};
|
|
|
|
void() DM_PhoenixBeamEnd =
|
|
{
|
|
if (self.enemy != world) {
|
|
self.enemy.x_flags = self.enemy.x_flags - (self.enemy.x_flags & X_TRACTOR_BEAM_HOLD);
|
|
self.enemy.velocity = normalize(self.enemy.origin - self.origin) * 250 + '0 0 100';
|
|
|
|
// hurt enemy
|
|
// damage is now inflicted by smashing them against a wall
|
|
T_Damage(self.enemy, self, self, 10);
|
|
self.enemy.touch = SUB_Null;
|
|
|
|
self.enemy.punchangle_x = -8;
|
|
|
|
self.enemy = world;
|
|
}
|
|
|
|
if (self.move_ent != world) {
|
|
remove(self.move_ent.flame_ent1);
|
|
remove(self.move_ent.flame_ent2);
|
|
remove(self.move_ent.flame_ent3);
|
|
remove(self.move_ent);
|
|
|
|
self.move_ent = world;
|
|
}
|
|
};
|
|
|
|
void() DM_PhoenixFireHoming =
|
|
{
|
|
local entity missile, missile_enemy;
|
|
local vector dir;
|
|
|
|
missile = spawn ();
|
|
missile.classname = "dm_phoenix_blast";
|
|
missile.attack_finished = time + 3;
|
|
missile.owner = self;
|
|
missile.movetype = MOVETYPE_FLYMISSILE;
|
|
missile.solid = SOLID_BBOX;
|
|
|
|
missile.think = GuidedRocketThink;
|
|
missile.last_guided_search = time;
|
|
missile.nextthink = time + 0.05;
|
|
|
|
// set missile speed
|
|
makevectors(self.v_angle);
|
|
|
|
missile.velocity = v_forward;
|
|
missile.velocity = missile.velocity * 800;
|
|
missile.angles = vectoangles(missile.velocity);
|
|
missile.angles_x = -1 * missile.angles_x;
|
|
|
|
missile.touch = T_GuidedMissileTouch;
|
|
|
|
missile.avelocity_z = 300;
|
|
|
|
setmodel (missile, "progs/psyblast.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
setorigin (missile, self.origin + dir*8 + '0 0 12');
|
|
|
|
sound(self, CHAN_WEAPON, "cannon/takeoff.wav", 1, ATTN_NORM);
|
|
};
|
|
|
|
// **************************************************************************
|
|
|
|
void() DoSpecialWeaponStuff =
|
|
{
|
|
local float frame_num;
|
|
|
|
frame_num = self.weaponframe - 6;
|
|
|
|
if (self.character == CHAR_WOLVERINE) {
|
|
if (!self.special_weapon) {
|
|
if (frame_num == 5)
|
|
Wolvy_Melee(200);
|
|
else if (frame_num == 9)
|
|
Wolvy_Melee(-200);
|
|
}
|
|
else {
|
|
if (frame_num == 1) // jump now
|
|
Wolvy_Jump();
|
|
else if ((frame_num >= 7) && (frame_num <= 10))
|
|
Wolvy_JumpThink ();
|
|
}
|
|
}
|
|
else if (self.character == CHAR_STORM) {
|
|
if (!self.special_weapon) {
|
|
if (frame_num == 5)
|
|
Storm_Wind();
|
|
}
|
|
else {
|
|
if ((frame_num >= 7) && (frame_num <= 10))
|
|
Storm_Lightning();
|
|
if (frame_num == 7)
|
|
sound (self, CHAN_WEAPON, "storm/l_attack.wav", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
else if (self.character == CHAR_CYCLOPS) {
|
|
if (!self.special_weapon) { // Fast Laser
|
|
if ((frame_num == 2) || (frame_num == 7))
|
|
DM_Cyclops_Fast_Laser();
|
|
}
|
|
else { // Big Laser Blast
|
|
if (frame_num == 8)
|
|
DM_Cyclops_Big_Laser();
|
|
}
|
|
}
|
|
else if (self.character == CHAR_PSYLOCKE) {
|
|
if (!self.special_weapon) { // Sword Attack
|
|
if ((frame_num == 2) || (frame_num == 7))
|
|
DM_Psylocke_Sword();
|
|
}
|
|
else { // Parallize Attack
|
|
if (frame_num == 8)
|
|
DM_Psylocke_Parallize();
|
|
}
|
|
}
|
|
else if (self.character == CHAR_ANGEL) {
|
|
if (!self.special_weapon) { // Throw Darts
|
|
if ((frame_num >= 3) && (frame_num <= 9)) {
|
|
DM_AngelFeather( (frame_num - 6) * 5 );
|
|
}
|
|
}
|
|
else { // Wing Defense
|
|
if (frame_num == 5) {
|
|
self.x_flags = self.x_flags | X_ANGEL_DEFENSE;
|
|
self.flags = self.flags | FL_GODMODE;
|
|
}
|
|
else if ((frame_num == 10) && (self.button0)) // stay at this frame while button down
|
|
self.weaponframe = self.weaponframe - 1;
|
|
else if (frame_num == 11) {
|
|
self.x_flags = self.x_flags - (self.x_flags & X_ANGEL_DEFENSE);
|
|
self.flags = self.flags - (self.flags & FL_GODMODE);
|
|
}
|
|
}
|
|
}
|
|
else if (self.character == CHAR_BEAST) {
|
|
if (!self.special_weapon) { // Double Punch
|
|
if ((frame_num == 4) ||
|
|
(frame_num == 7) ||
|
|
(frame_num == 10)) {
|
|
DM_BeastPunch();
|
|
}
|
|
}
|
|
else { // Floor Pound
|
|
if (frame_num == 4) { // give some jump
|
|
if (self.flags & FL_ONGROUND)
|
|
self.velocity_z = 190;
|
|
}
|
|
else if (frame_num == 11) {
|
|
DM_BeastPound();
|
|
}
|
|
}
|
|
}
|
|
else if (self.character == CHAR_GAMBIT) {
|
|
if (!self.special_weapon) { // Staff Attack
|
|
if (frame_num == 7)
|
|
DM_Gambit_Strike();
|
|
else if (frame_num == 3)
|
|
sound (self, CHAN_WEAPON, "generic/swing1.wav", 1, ATTN_NORM);
|
|
}
|
|
else { // Throw Cards
|
|
if ((frame_num >= 5) && (frame_num <= 7)) {
|
|
DM_GambitCard( (frame_num - 6) * -5, 12 );
|
|
}
|
|
if (frame_num == 4)
|
|
sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
else if (self.character == CHAR_ICEMAN) {
|
|
if (!self.special_weapon) { // Small Shards
|
|
if ((frame_num >= 3) && (frame_num <= 8)) {
|
|
DM_Iceman_Shard( (frame_num - 6) * 4 );
|
|
}
|
|
}
|
|
else { // Big Freeze
|
|
if (frame_num == 10)
|
|
DM_Iceman_Iceball();
|
|
}
|
|
}
|
|
else if (self.character == CHAR_BISHOP) {
|
|
if (!self.special_weapon) { // Dual Guns
|
|
if (frame_num == 2)
|
|
DM_Bishop_Shoot(6);
|
|
else if (frame_num == 7)
|
|
DM_Bishop_Shoot(-6);
|
|
}
|
|
else {
|
|
if (frame_num == 5)
|
|
DM_Bishop_Special();
|
|
}
|
|
}
|
|
else if (self.character == CHAR_ROGUE) {
|
|
if (!self.special_weapon) { // Dual Punch
|
|
if ((frame_num == 4) ||
|
|
(frame_num == 10))
|
|
DM_Rogue_Punch(10);
|
|
}
|
|
else { // Flying Punch
|
|
if (frame_num == 2) {
|
|
self.last_special = time;
|
|
}
|
|
else if (frame_num == 3) {
|
|
if (self.button0) {
|
|
self.x_flags = self.x_flags | X_FLYING;
|
|
self.flags = self.flags | FL_ONGROUND;
|
|
|
|
DM_Rogue_Fly();
|
|
|
|
if (self.last_special > (time - 5) && (trace_ent.classname != "player"))
|
|
self.weaponframe = self.weaponframe - 1;
|
|
}
|
|
}
|
|
else if (frame_num == 6) {
|
|
self.x_flags = self.x_flags - (self.x_flags & X_FLYING);
|
|
}
|
|
}
|
|
}
|
|
else if (self.character == CHAR_CANNONBALL) {
|
|
if (!self.special_weapon) { // Punch
|
|
if (frame_num == 6)
|
|
DM_Cannon_Punch(10);
|
|
}
|
|
else { // Flying Punch
|
|
if (frame_num == 1) {
|
|
sound(self, CHAN_ITEM, "cannon/takeoff.wav", 1, ATTN_NORM);
|
|
}
|
|
|
|
if (frame_num < 6) {
|
|
self.last_special = time;
|
|
self.x_flags = self.x_flags | X_FLYING;
|
|
self.effects = self.effects | EF_DIMLIGHT;
|
|
self.velocity_z = self.old_velocity_z = 100;
|
|
}
|
|
else if (frame_num < 9) {
|
|
self.flags = self.flags | FL_ONGROUND;
|
|
DM_Cannon_Fly();
|
|
|
|
if ((self.button0) && (trace_fraction == 1) && (frame_num == 8) && (self.last_special > (time - 5))) {
|
|
self.weaponframe = self.weaponframe - 3;
|
|
}
|
|
}
|
|
else if (frame_num == 9) {
|
|
self.last_special2 = time;
|
|
self.attack_finished = time + 2;
|
|
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
|
// DM_Cannon_Punch(30 + random()*15);
|
|
self.x_flags = self.x_flags - (self.x_flags & X_FLYING);
|
|
}
|
|
}
|
|
}
|
|
else if (self.character == CHAR_PHOENIX) {
|
|
if (!self.special_weapon) { // Tractor Beam
|
|
if (frame_num == 1)
|
|
self.enemy = world;
|
|
else if (frame_num < 6) {
|
|
if (self.enemy == world) {
|
|
makevectors(self.v_angle);
|
|
traceline(self.origin + '0 0 16', self.origin + '0 0 16' + v_forward * 512, FALSE, self);
|
|
|
|
if (((trace_ent.touch == ammo_touch) ||
|
|
(trace_ent.classname == "guided_rocket") ||
|
|
(trace_ent.classname == "orb") ||
|
|
(trace_ent.flags & FL_MONSTER) ||
|
|
(trace_ent.classname == "player")) && (trace_ent != self))
|
|
self.enemy = trace_ent;
|
|
else
|
|
self.enemy = world;
|
|
}
|
|
}
|
|
else if (frame_num == 6) {
|
|
if (self.enemy != world) {
|
|
DM_PhoenixStartBeam();
|
|
}
|
|
}
|
|
else if (frame_num == 8) {
|
|
if ((self.enemy != world) && (self.start_attack_health <= self.health) && (self.start_tractor_time > (time - 4)) && (self.button0) && (self.flags & FL_GODMODE)) {
|
|
traceline(self.origin, self.enemy.origin, TRUE, world);
|
|
if (trace_fraction == 1)
|
|
self.weaponframe = self.weaponframe - 1;
|
|
}
|
|
}
|
|
else if (frame_num == 9) {
|
|
DM_PhoenixBeamEnd();
|
|
self.flags = self.flags - (self.flags & FL_GODMODE);
|
|
self.enemy = world;
|
|
}
|
|
}
|
|
else { // Homing missile
|
|
if (frame_num == 4)
|
|
DM_PhoenixFireHoming();
|
|
}
|
|
}
|
|
};
|