3169 lines
80 KiB
C
3169 lines
80 KiB
C
/*
|
|
*/
|
|
void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
|
|
void () player_run;
|
|
void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
|
|
void(vector org, vector vel, float damage) SpawnBlood;
|
|
void() SuperDamageSound;
|
|
|
|
void() player_stand1;
|
|
|
|
// entity values for chasecam purposes
|
|
.vector last_roll;
|
|
.entity chasecam;
|
|
.float tracking_speed;
|
|
.float chasecam_zoom;
|
|
.float last_weapon_channel;
|
|
|
|
float DEFAULT_TRACKING_SPEED = 0;
|
|
vector CHASECAM_CLOSE = '16 0 16';
|
|
//vector CHASECAM_FAR = '20 0 48';
|
|
float chasecam_alt, chasecam_dist = 16, chasecam_zofs = 6;
|
|
|
|
|
|
// called by worldspawn
|
|
void() W_Precache =
|
|
{
|
|
precache_sound ("weapons/r_exp3.wav"); // new rocket explosion
|
|
precache_sound ("weapons/rocket1i.wav"); // spike gun
|
|
precache_sound ("weapons/sgun1.wav");
|
|
precache_sound ("weapons/guncock.wav"); // player shotgun
|
|
precache_sound ("weapons/ric1.wav"); // ricochet (used in c code)
|
|
precache_sound ("weapons/ric2.wav"); // ricochet (used in c code)
|
|
precache_sound ("weapons/ric3.wav"); // ricochet (used in c code)
|
|
precache_sound ("weapons/spike2.wav"); // super spikes
|
|
precache_sound ("weapons/tink1.wav"); // spikes tink (used in c code)
|
|
precache_sound ("weapons/grenade.wav"); // grenade launcher
|
|
precache_sound ("weapons/bounce.wav"); // grenade bounce
|
|
precache_sound ("weapons/shotgn2.wav"); // super shotgun
|
|
};
|
|
|
|
float() crandom =
|
|
{
|
|
return 2*(random() - 0.5);
|
|
};
|
|
|
|
/*
|
|
================
|
|
W_FireAxe
|
|
================
|
|
*/
|
|
void() W_FireAxe =
|
|
{
|
|
local vector source;
|
|
local vector org;
|
|
|
|
self.punchangle_y = -8;
|
|
self.punchangle_x = -4;
|
|
self.punchangle_z = 0;
|
|
|
|
makevectors (self.v_angle);
|
|
source = self.origin + '0 0 16';
|
|
traceline (source, source + v_forward*64, FALSE, self);
|
|
if (trace_fraction == 1.0)
|
|
return;
|
|
|
|
org = trace_endpos - v_forward*4;
|
|
|
|
if (trace_ent.takedamage)
|
|
{
|
|
trace_ent.axhitme = 1;
|
|
SpawnBlood (org, '0 0 0', 20);
|
|
T_Damage (trace_ent, self, self, 20);
|
|
}
|
|
else
|
|
{ // hit wall
|
|
sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
|
|
WriteCoord (MSG_BROADCAST, org_x);
|
|
WriteCoord (MSG_BROADCAST, org_y);
|
|
WriteCoord (MSG_BROADCAST, org_z);
|
|
}
|
|
};
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
vector() wall_velocity =
|
|
{
|
|
local vector vel;
|
|
/*
|
|
vel = normalize (self.velocity);
|
|
vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
|
|
vel = vel + 2*trace_plane_normal;
|
|
vel = vel * 200;
|
|
*/
|
|
makevectors(other.angles);
|
|
vel = normalize(v_forward*(random() - 0.85) + v_up*(random() - 0.5) + v_right*(random() - 0.5));
|
|
vel = vel * 300;
|
|
|
|
return vel;
|
|
};
|
|
|
|
//float SLIDE_SPEED = 1;
|
|
|
|
void() BloodWallSlide =
|
|
{
|
|
local vector pt1;
|
|
|
|
if (self.attack_finished < time) {
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
pt1 = self.origin + self.v_angle*8;
|
|
traceline(pt1, pt1 - '0 0 0.5', TRUE, self);
|
|
if (trace_fraction < 1) {
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
pt1 = trace_endpos;
|
|
traceline(pt1, pt1 - (self.v_angle*12), TRUE, self);
|
|
setorigin(self, trace_endpos);
|
|
//bprint("blood wall slide\n");
|
|
self.last_blood_think = time;
|
|
self.nextthink = time + 0.1;
|
|
};
|
|
|
|
void() BloodTouch =
|
|
{
|
|
local vector dir;
|
|
|
|
if (other != world) {
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
//bprint("blood touch\n");
|
|
|
|
dir = normalize(self.velocity);
|
|
makevectors(dir);
|
|
traceline(self.origin - dir*4, self.origin + dir*12, TRUE, self);
|
|
if ((trace_fraction < 1) && (fabs(trace_plane_normal_z) < 0.2)) {
|
|
// start sliding down wall
|
|
self.movetype = MOVETYPE_NONE;
|
|
self.velocity = '0 0 0';
|
|
self.v_angle = trace_plane_normal;
|
|
self.last_blood_think = time;
|
|
self.frame = self.frame + 1;
|
|
self.think = BloodWallSlide;
|
|
self.nextthink = time + 0.1;
|
|
self.attack_finished = time + 7;
|
|
self.angles = vectoangles(trace_plane_normal);
|
|
}
|
|
};
|
|
|
|
/*
|
|
================
|
|
SpawnMeatSpray
|
|
================
|
|
*/
|
|
void(vector org, vector vel) SpawnMeatSpray =
|
|
{
|
|
local entity missile, mpuff;
|
|
local vector org;
|
|
|
|
missile = spawn ();
|
|
missile.owner = self;
|
|
missile.movetype = MOVETYPE_BOUNCE;
|
|
missile.solid = SOLID_BBOX;
|
|
|
|
makevectors (self.angles);
|
|
|
|
missile.velocity = vel;
|
|
missile.velocity_z = missile.velocity_z + 150 + 50*random();
|
|
|
|
missile.avelocity = '300 100 200';
|
|
|
|
missile.touch = BloodTouch;
|
|
|
|
// set missile duration
|
|
missile.nextthink = time + 5;
|
|
missile.think = SUB_Remove;
|
|
|
|
setmodel (missile, "progs/blood.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
setorigin (missile, org);
|
|
};
|
|
|
|
/*
|
|
================
|
|
SpawnBlood
|
|
================
|
|
*/
|
|
void(vector org, vector vel, float damage) SpawnBlood =
|
|
{
|
|
local vector vrand, vect;
|
|
local float num_gibs;
|
|
|
|
particle (org, vel* -0.1, 73, damage*2);
|
|
|
|
if (deathmatch) { // preserve bandwidth
|
|
return;
|
|
}
|
|
|
|
num_gibs = ceil(damage / 15);
|
|
|
|
while (num_gibs > 0) {
|
|
vrand = '8 0 0' * random() + '0 8 0' * random() + '0 0 4' * random() - '4 4 2';
|
|
vect = normalize(vrand + vel);
|
|
SpawnMeatSpray(org + vect*24, vect*(100 + random()*400));
|
|
num_gibs = num_gibs - 1;
|
|
}
|
|
};
|
|
|
|
/*
|
|
================
|
|
spawn_touchblood
|
|
================
|
|
*/
|
|
void(float damage) spawn_touchblood =
|
|
{
|
|
local vector vel, vrand;
|
|
local float num_gibs;
|
|
|
|
vel = wall_velocity () * 0.2;
|
|
|
|
if (deathmatch) {
|
|
SpawnBlood (self.origin + vel*0.01, vel, damage);
|
|
return;
|
|
}
|
|
|
|
num_gibs = damage / 10;
|
|
|
|
while (num_gibs > 0) {
|
|
vrand = '8 0 0' * random() + '0 8 0' * random() + '0 0 4' * random() - '4 4 2';
|
|
SpawnMeatSpray(self.origin + vrand + vel*0.01, vel + vrand*20);
|
|
num_gibs = num_gibs - 1;
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
================
|
|
SpawnChunk
|
|
================
|
|
*/
|
|
void(vector org, vector vel) SpawnChunk =
|
|
{
|
|
// particle (org, vel*0.02, 0, 10);
|
|
SpawnBlood(org, vel*0.02, 5);
|
|
};
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
MULTI-DAMAGE
|
|
|
|
Collects multiple small damages into a single damage
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
entity multi_ent;
|
|
float multi_damage;
|
|
|
|
void() ClearMultiDamage =
|
|
{
|
|
multi_ent = world;
|
|
multi_damage = 0;
|
|
};
|
|
|
|
void() ApplyMultiDamage =
|
|
{
|
|
if (!multi_ent)
|
|
return;
|
|
T_Damage (multi_ent, self, self, multi_damage);
|
|
};
|
|
|
|
void(entity hit, float damage) AddMultiDamage =
|
|
{
|
|
if (!hit)
|
|
return;
|
|
|
|
if (hit != multi_ent)
|
|
{
|
|
ApplyMultiDamage ();
|
|
multi_damage = damage;
|
|
multi_ent = hit;
|
|
}
|
|
else
|
|
multi_damage = multi_damage + damage;
|
|
};
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
BULLETS
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
TraceAttack
|
|
================
|
|
*/
|
|
void(entity ent, float num_gibs) IcemanShardGib;
|
|
void(float damage, vector dir) TraceAttack =
|
|
{
|
|
local vector vel, org;
|
|
|
|
vel = normalize(dir*5 + v_up*random() + v_right*crandom());
|
|
// vel = vel + 2*trace_plane_normal;
|
|
// vel = normalize(vel);
|
|
|
|
org = trace_endpos - dir*4;
|
|
|
|
if (trace_ent.takedamage)
|
|
{
|
|
org = trace_ent.origin;
|
|
if ((trace_ent.classname != "xmen_sinister") || (trace_ent.x_flags & X_MEGA_HIT)) {
|
|
if ((trace_ent.classname != "xmen_iceman") && (trace_ent.character != CHAR_ICEMAN)) {
|
|
if ((trace_ent.flags & FL_MONSTER) ||
|
|
(trace_ent.flags & FL_CLIENT)) {
|
|
if (random() < 0.8)
|
|
SpawnBlood (org, vel * 12, damage);
|
|
else
|
|
SpawnBlood (org, vel * -2, damage);
|
|
}
|
|
}
|
|
else {
|
|
IcemanShardGib(trace_ent, damage / 6);
|
|
}
|
|
}
|
|
|
|
AddMultiDamage (trace_ent, damage);
|
|
}
|
|
else
|
|
{
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
|
|
WriteCoord (MSG_BROADCAST, org_x);
|
|
WriteCoord (MSG_BROADCAST, org_y);
|
|
WriteCoord (MSG_BROADCAST, org_z);
|
|
}
|
|
};
|
|
|
|
/*
|
|
================
|
|
FireBullets
|
|
|
|
Used by shotgun, super shotgun, and enemy soldier firing
|
|
Go to the trouble of combining multiple pellets into a single damage call.
|
|
================
|
|
*/
|
|
void(float shotcount, vector dir, vector spread) FireBullets =
|
|
{
|
|
local vector direction;
|
|
local vector src;
|
|
|
|
makevectors(self.v_angle);
|
|
|
|
src = self.origin + v_forward*10 + '0 0 12';
|
|
src_z = self.absmin_z + self.size_z * 0.7;
|
|
|
|
ClearMultiDamage ();
|
|
while (shotcount > 0)
|
|
{
|
|
direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
|
|
|
|
traceline (src, src + direction*2048, FALSE, self);
|
|
if (trace_fraction != 1.0)
|
|
TraceAttack (4, direction);
|
|
|
|
shotcount = shotcount - 1;
|
|
}
|
|
ApplyMultiDamage ();
|
|
};
|
|
|
|
/*
|
|
================
|
|
W_FireShotgun
|
|
================
|
|
*/
|
|
void() W_FireShotgun =
|
|
{
|
|
local vector dir;
|
|
|
|
sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
|
|
|
|
self.punchangle_x = -2;
|
|
|
|
self.currentammo = self.ammo_shells = self.ammo_shells - 1;
|
|
dir = aim (self, 100000);
|
|
FireBullets (6, dir, '0.04 0.04 0');
|
|
};
|
|
|
|
|
|
/*
|
|
================
|
|
W_FireSuperShotgun
|
|
================
|
|
*/
|
|
void() W_FireSuperShotgun =
|
|
{
|
|
local float rnd;
|
|
local vector dir;
|
|
|
|
if (self.currentammo <= 1)
|
|
self.currentammo = self.ammo_shells = 0;
|
|
else
|
|
self.currentammo = self.ammo_shells = self.ammo_shells - 1;
|
|
|
|
sound (self ,CHAN_WEAPON, "weapons/shotfir6.wav", 1, ATTN_NORM);
|
|
|
|
self.punchangle_x = -8;
|
|
|
|
dir = aim (self, 100000);
|
|
FireBullets (7, dir, '0.06 0.06 0');
|
|
|
|
if (vlen(self.velocity) < 10) { // add some bounce if stationery
|
|
self.velocity = self.velocity + '0 0 150';
|
|
}
|
|
|
|
v_forward_z = 0;
|
|
self.velocity = self.velocity - (v_forward * 40);
|
|
|
|
};
|
|
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
ROCKETS
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
void() s_explode1 = [0, s_explode2] {};
|
|
void() s_explode2 = [1, s_explode3] {self.effects = self.effects | EF_DIMLIGHT;};
|
|
void() s_explode3 = [2, s_explode4] {};
|
|
void() s_explode4 = [3, s_explode5] {self.effects = self.effects - EF_DIMLIGHT;};
|
|
void() s_explode5 = [4, s_explode6] {};
|
|
void() s_explode6 = [5, SUB_Remove] {};
|
|
|
|
void() BecomeExplosion =
|
|
{
|
|
self.movetype = MOVETYPE_NONE;
|
|
self.velocity = '0 0 0';
|
|
self.touch = SUB_Null;
|
|
setmodel (self, "progs/s_explod.spr");
|
|
self.solid = SOLID_NOT;
|
|
s_explode1 ();
|
|
};
|
|
|
|
void() T_MissileTouch =
|
|
{
|
|
local float damg;
|
|
|
|
if (other == self.owner)
|
|
return; // don't explode on owner
|
|
|
|
if (pointcontents(self.origin) == CONTENT_SKY)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
damg = 100 + random()*20;
|
|
|
|
if (other.health)
|
|
{
|
|
if (other.classname == "xmen_storm")
|
|
damg = damg * 0.5; // mostly immune
|
|
T_Damage (other, self, self.owner, damg );
|
|
}
|
|
|
|
// don't do radius damage to the other, because all the damage
|
|
// was done in the impact
|
|
T_RadiusDamage (self, self.owner, 120, other);
|
|
|
|
// sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
|
|
self.origin = self.origin - 8*normalize(self.velocity);
|
|
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
|
|
BecomeExplosion ();
|
|
};
|
|
|
|
void() cannon_xatta16;
|
|
void() T_GuidedMissileTouch =
|
|
{
|
|
local float damg;
|
|
|
|
if (other == self.owner)
|
|
return; // don't explode on owner
|
|
|
|
if (pointcontents(self.origin) == CONTENT_SKY)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
if (self.dmg == 0)
|
|
damg = 35 + random()*5;
|
|
else
|
|
damg = self.dmg;
|
|
|
|
if (self.classname == "dm_phoenix_blast")
|
|
damg = damg / 2;
|
|
|
|
if (self.classname == "phoenix_blast")
|
|
damg = damg / 2;
|
|
|
|
if ((other.classname == "xmen_cannonball") && (other.flags & FL_GODMODE)) {
|
|
if (other.last_rocket_hit > (time - 0.5)) {
|
|
other.x_flags = other.x_flags | X_CANNONFLYABORT;
|
|
// other.think = cannon_xatta16;
|
|
}
|
|
|
|
}
|
|
|
|
if (other != world)
|
|
other.last_rocket_hit = time;
|
|
|
|
if (other.health)
|
|
{
|
|
if (!(other.x_flags & X_ANGEL_DEFENSE))
|
|
T_Damage (other, self, self.owner, damg );
|
|
|
|
if ((other.movetype) && (other.flags & FL_ONGROUND) && (other.classname != "apocalypse_small") && (other.classname != "xmen_sinister")) { // give some velocity
|
|
other.velocity = other.velocity + normalize(self.velocity) * 180;
|
|
if (other.velocity_z < 140)
|
|
other.velocity_z = 140;
|
|
other.flags = other.flags - (other.flags & FL_ONGROUND);
|
|
setorigin(other, other.origin + '0 0 1');
|
|
}
|
|
}
|
|
|
|
if (self.classname != "phoenix_blast") {
|
|
// don't do radius damage to the other, because all the damage
|
|
// was done in the impact
|
|
T_RadiusDamage (self, self.owner, 40, other);
|
|
}
|
|
|
|
sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 0.6, ATTN_NORM);
|
|
self.origin = self.origin - 8*normalize(self.velocity);
|
|
|
|
BecomeExplosion ();
|
|
};
|
|
|
|
/*******************************
|
|
FindSightEnemy
|
|
Returns an entity that is within "angle_range" of "dir"
|
|
use filter_classname to exclude all entitys with the given classname
|
|
from being returned (use "world" to for to include all classes)
|
|
*******************************/
|
|
|
|
entity(vector org, vector dir, float dist, float angle_range, string filter_class, entity ignore) FindSightEnemy =
|
|
{
|
|
local entity trav;
|
|
local float trav_yaw, dir_yaw;
|
|
|
|
dir_yaw = vectoyaw(dir);
|
|
|
|
trav = findradius(org, dist);
|
|
|
|
while (trav != world) {
|
|
if (((filter_class == "all") || (filter_class == trav.classname)) && (trav != ignore) && ((ignore != world) && (trav != ignore.owner))) {
|
|
if ((trav.takedamage == DAMAGE_AIM)
|
|
&& (trav.health > 0)) {
|
|
|
|
// make sure trav is within the angle_range
|
|
trav_yaw = vectoyaw(trav.origin - org);
|
|
if (fabs(angle_diff(dir_yaw, trav_yaw)) <= angle_range) {
|
|
// check there is a clear line of sight
|
|
traceline(org, trav.origin, TRUE, world);
|
|
if (trace_fraction == 1) {
|
|
return trav;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
trav = trav.chain;
|
|
}
|
|
|
|
return trav;
|
|
};
|
|
|
|
void() T_MissileTouch;
|
|
|
|
// lower weight, means more accurate
|
|
void(vector target_org, float weight) RocketSeek =
|
|
{
|
|
local float current_speed;
|
|
local vector target_vector, vel, unit_velocity;
|
|
|
|
current_speed = vlen(self.velocity);
|
|
|
|
target_vector = normalize(target_org - self.origin);
|
|
unit_velocity = normalize(self.velocity);
|
|
self.velocity = normalize(target_vector + unit_velocity*weight) * current_speed;
|
|
vel = normalize(self.velocity);
|
|
self.angles = vectoangles(vel);
|
|
|
|
self.nextthink = time + 0.05;
|
|
};
|
|
|
|
void() GuidedRocketThink =
|
|
{
|
|
local vector dir, new_targ, reflect, endpos;
|
|
local float interdist;
|
|
|
|
if (self.attack_finished < time) {
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
dir = normalize(self.velocity);
|
|
self.angles = vectoangles(dir);
|
|
self.angles_x = -1 * self.angles_x;
|
|
|
|
if (self.classname == "prox_missile")
|
|
particle(self.origin, self.velocity * 0.5, 44, 10);
|
|
|
|
if (self.enemy != world) {
|
|
if ((self.enemy.health <= 0) ||
|
|
((self.enemy.classname == "xmen_phoenix") &&
|
|
(self.enemy.flags & FL_GODMODE))) {
|
|
self.enemy = world;
|
|
}
|
|
else
|
|
{
|
|
traceline(self.origin, self.enemy.origin, TRUE, self);
|
|
if (trace_fraction == 1) { // clear path
|
|
if (self.classname == "prox_missile")
|
|
RocketSeek(self.enemy.origin, 0.5);
|
|
else if (self.classname == "dm_phoenix_blast")
|
|
RocketSeek(self.enemy.origin, 8);
|
|
else
|
|
RocketSeek(self.enemy.origin, 5);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if ((self.enemy == world) && (self.last_guided_search < (time - 0.2))) // search for a new target every 0.5 seconds
|
|
{
|
|
makevectors(self.angles);
|
|
dir = v_forward;
|
|
|
|
if (self.classname == "pheonix_blast")
|
|
self.enemy = FindSightEnemy(self.origin, dir, 1500, 30, "player", self);
|
|
else
|
|
self.enemy = FindSightEnemy(self.origin, dir, 1500, 30, "all", self);
|
|
self.last_guided_search = time;
|
|
}
|
|
|
|
// avoid walls
|
|
dir = normalize(self.velocity);
|
|
traceline(self.origin, self.origin + dir*256, TRUE, self);
|
|
if ((trace_fraction < 1) && (trace_ent == world)) { // heading for a wall
|
|
endpos = trace_endpos;
|
|
interdist = 256 * trace_fraction;
|
|
// reflect = GetReflectionVect(trace_endpos, dir, trace_plane_normal);
|
|
new_targ = endpos + trace_plane_normal * interdist;
|
|
RocketSeek(new_targ, 3);
|
|
return;
|
|
}
|
|
|
|
self.nextthink = time + 0.05;
|
|
};
|
|
|
|
void() GuidedRocketStart =
|
|
{
|
|
local entity missile_enemy;
|
|
local vector dir;
|
|
|
|
dir = normalize(self.velocity);
|
|
|
|
if (self.enemy == world) {
|
|
if ((missile_enemy = FindSightEnemy(self.origin, dir, 1500, 30, "all", self.owner)) != world) {
|
|
self.enemy = missile_enemy;
|
|
|
|
if (missile_enemy.th_guard) {
|
|
if (missile_enemy.enemy == self.owner) { // alert Enemy
|
|
missile_enemy.guard_flag = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
self.velocity = self.old_velocity + normalize(self.velocity) * 3;
|
|
self.velocity = normalize(self.velocity);
|
|
self.angles = vectoangles(self.velocity);
|
|
self.angles_x = -1 * self.angles_x;
|
|
self.velocity = self.velocity * 500;
|
|
}
|
|
}
|
|
|
|
self.think = GuidedRocketThink;
|
|
self.nextthink = time + 0.05;
|
|
};
|
|
|
|
void(vector origdir, vector ofs) GuidedMissile =
|
|
{
|
|
local entity missile, missile_enemy;
|
|
local vector dir;
|
|
|
|
missile = spawn ();
|
|
missile.classname = "guided_rocket";
|
|
missile.attack_finished = time + 3;
|
|
missile.owner = self;
|
|
missile.movetype = MOVETYPE_FLYMISSILE;
|
|
missile.solid = SOLID_BBOX;
|
|
|
|
// dir = normalize(origdir);
|
|
|
|
dir = v_forward;
|
|
|
|
if ((missile_enemy = FindSightEnemy(missile.origin, dir, 1500, 30, "all", self)) != world) {
|
|
self.enemy = missile_enemy;
|
|
|
|
if (missile_enemy.th_guard) {
|
|
if (missile_enemy.enemy == self) { // alert Enemy
|
|
missile_enemy.guard_flag = TRUE;
|
|
}
|
|
}
|
|
}
|
|
missile.think = GuidedRocketStart;
|
|
missile.last_guided_search = time;
|
|
missile.nextthink = time + 0.3;
|
|
|
|
missile.old_velocity = normalize(origdir);
|
|
|
|
// set missile speed
|
|
|
|
missile.velocity = dir;
|
|
missile.velocity = missile.velocity * 500;
|
|
missile.angles = vectoangles(missile.velocity);
|
|
|
|
missile.touch = T_GuidedMissileTouch;
|
|
|
|
setmodel (missile, "progs/missmall.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
setorigin (missile, self.origin + origdir + ofs + v_forward * 8 + '0 0 16');
|
|
};
|
|
|
|
void() W_FireGuidedRockets =
|
|
{
|
|
if (self.ammo_rockets <= 2)
|
|
self.currentammo = self.ammo_rockets = 0;
|
|
else
|
|
self.currentammo = self.ammo_rockets = self.ammo_rockets - 2;
|
|
|
|
sound (self, CHAN_WEAPON, "weapons/guidfire.wav", 1, ATTN_NORM);
|
|
self.punchangle_x = -12;
|
|
|
|
makevectors (self.v_angle);
|
|
/*
|
|
GuidedMissile(v_forward*3 + v_up);
|
|
GuidedMissile(v_forward*3 + v_right);
|
|
GuidedMissile(v_forward*3 - v_right);
|
|
*/
|
|
// GuidedMissile(v_forward*5 - v_right);
|
|
// GuidedMissile(v_forward*5 + v_right);
|
|
GuidedMissile(v_right * 2, v_right * 6);
|
|
GuidedMissile(v_right * -2, v_right * 6);
|
|
};
|
|
|
|
/*
|
|
================
|
|
W_FireRocket
|
|
================
|
|
*/
|
|
void() W_FireRocket =
|
|
{
|
|
local entity missile, mpuff;
|
|
|
|
// self.currentammo = self.ammo_rockets = self.ammo_rockets - 3;
|
|
|
|
// sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
|
|
|
|
self.punchangle_x = -2;
|
|
|
|
missile = spawn ();
|
|
missile.owner = self;
|
|
missile.movetype = MOVETYPE_FLYMISSILE;
|
|
missile.solid = SOLID_BBOX;
|
|
missile.classname = "missile";
|
|
|
|
// set missile speed
|
|
|
|
makevectors (self.v_angle);
|
|
missile.velocity = aim(self, 1000);
|
|
missile.velocity = missile.velocity * 1000;
|
|
missile.angles = vectoangles(missile.velocity);
|
|
|
|
missile.touch = T_MissileTouch;
|
|
|
|
// set missile duration
|
|
missile.nextthink = time + 5;
|
|
missile.think = SUB_Remove;
|
|
|
|
setmodel (missile, "progs/missile.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
setorigin (missile, self.origin + v_forward*8 + '0 0 16');
|
|
|
|
W_FireGuidedRockets();
|
|
};
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
LIGHTNING
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
.float remove_time;
|
|
|
|
void() bolt_think =
|
|
{
|
|
self.angles_z = random() * 340 - 170;
|
|
|
|
if (self.remove_time < time)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
self.frame = self.speed;
|
|
self.nextthink = time + 0.05;
|
|
};
|
|
|
|
void(vector start, vector end, string modelstr, vector angle_ofs, float bolt_life) FillBetweenPoints =
|
|
{
|
|
local vector org, dir, dir_angle;
|
|
local float dist;
|
|
local entity newbolt;
|
|
|
|
dist = vlen(start - end);
|
|
dir = normalize(end - start);
|
|
dir_angle = vectoangles(dir);
|
|
org = start;
|
|
|
|
while (vlen(org - start) < dist)
|
|
{
|
|
//bprint("b");
|
|
newbolt = spawn();
|
|
setmodel(newbolt, modelstr);
|
|
setorigin(newbolt, org);
|
|
newbolt.frame = 0; //frame_num;
|
|
newbolt.speed = 0; //frame_num;
|
|
newbolt.angles = dir_angle + angle_ofs;
|
|
newbolt.angles_z = random() * 340 - 170;
|
|
newbolt.remove_time = time + bolt_life; //0.07;
|
|
newbolt.think = bolt_think;
|
|
newbolt.nextthink = time + 0.05;
|
|
|
|
if (modelstr == "progs/bolt3.mdl")
|
|
org = org + dir*128;
|
|
else
|
|
org = org + dir*32;
|
|
|
|
}
|
|
//bprint("\n");
|
|
};
|
|
|
|
/*
|
|
=================
|
|
LightningDamage
|
|
=================
|
|
*/
|
|
void(vector p1, vector p2, entity from, float damage) LightningDamage =
|
|
{
|
|
local entity e1, e2;
|
|
local vector f;
|
|
|
|
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)
|
|
{
|
|
particle (trace_endpos, '0 0 100', 225, damage*4);
|
|
T_Damage (trace_ent, from, from, damage);
|
|
if (self.classname == "player")
|
|
{
|
|
if (other.classname == "player")
|
|
trace_ent.velocity_z = trace_ent.velocity_z + 400;
|
|
}
|
|
}
|
|
e1 = trace_ent;
|
|
|
|
traceline (p1 + f, p2 + f, FALSE, self);
|
|
if (trace_ent != e1 && trace_ent.takedamage)
|
|
{
|
|
particle (trace_endpos, '0 0 100', 225, damage*4);
|
|
T_Damage (trace_ent, from, from, damage);
|
|
}
|
|
e2 = trace_ent;
|
|
|
|
traceline (p1 - f, p2 - f, FALSE, self);
|
|
if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
|
|
{
|
|
particle (trace_endpos, '0 0 100', 225, damage*4);
|
|
T_Damage (trace_ent, from, from, damage);
|
|
}
|
|
};
|
|
|
|
void(vector org_start, vector dir_start) ReflectLightning =
|
|
{
|
|
local float reflect_count, NUM_REFLECTIONS, frac, total_dist, MAX_DIST, length;
|
|
local vector org, dir, normal, endpos;
|
|
local entity ent, junction;
|
|
local string str;
|
|
|
|
NUM_REFLECTIONS = 2;
|
|
MAX_DIST = 800;
|
|
|
|
org = org_start;
|
|
dir = dir_start;
|
|
reflect_count = 0;
|
|
total_dist = 0;
|
|
junction = self;
|
|
|
|
while (reflect_count <= NUM_REFLECTIONS) {
|
|
traceline (org, org + dir*600, FALSE, self);
|
|
frac = trace_fraction;
|
|
ent = trace_ent;
|
|
normal = trace_plane_normal;
|
|
endpos = trace_endpos;
|
|
|
|
length = vlen(endpos - org);
|
|
if ((total_dist + length) > MAX_DIST) {
|
|
endpos = org + dir * (MAX_DIST - total_dist);
|
|
reflect_count = NUM_REFLECTIONS;
|
|
}
|
|
|
|
// if (trace_fraction < 0.05)
|
|
// return;
|
|
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
|
|
WriteEntity (MSG_BROADCAST, junction);
|
|
WriteCoord (MSG_BROADCAST, org_x);
|
|
WriteCoord (MSG_BROADCAST, org_y);
|
|
WriteCoord (MSG_BROADCAST, org_z);
|
|
WriteCoord (MSG_BROADCAST, endpos_x);
|
|
WriteCoord (MSG_BROADCAST, endpos_y);
|
|
WriteCoord (MSG_BROADCAST, endpos_z);
|
|
|
|
LightningDamage (org, endpos + dir*4, self, 30 * (1 - (total_dist/480))); // lose power over distance
|
|
|
|
//str = ftos(frac);
|
|
//bprint(str);
|
|
//bprint("\n");
|
|
if ((frac < 1) && (ent == world)) {
|
|
org = endpos;
|
|
dir = GetReflectionVect(org, dir, normal);
|
|
|
|
reflect_count = reflect_count + 1;
|
|
}
|
|
else {
|
|
reflect_count = NUM_REFLECTIONS + 1;
|
|
total_dist = MAX_DIST;
|
|
}
|
|
|
|
// junction = junction.beam_ent;
|
|
}
|
|
};
|
|
|
|
void() W_FireLightning =
|
|
{
|
|
local vector org;
|
|
local float cells;
|
|
|
|
stuffcmd(self, "bf\n");
|
|
self.punchangle = '-10 0 0' + '10 0 0' * random() + '0 10 0' * random() + '0 0 10' * random() - '5 5 5';
|
|
|
|
// self.currentammo = self.ammo_cells = self.ammo_cells - 1;
|
|
|
|
org = self.origin + '0 0 16';
|
|
|
|
makevectors(self.v_angle);
|
|
|
|
traceline(org, org + v_forward * 1000, FALSE, self);
|
|
|
|
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, trace_endpos_x);
|
|
WriteCoord (MSG_BROADCAST, trace_endpos_y);
|
|
WriteCoord (MSG_BROADCAST, trace_endpos_z);
|
|
|
|
if ((trace_ent != world) &&
|
|
!(trace_ent.x_flags & X_MEGA_HIT) &&
|
|
((trace_ent.owner.classname == "xmen_apocalypse") ||
|
|
(trace_ent.classname == "xmen_sinister"))) {
|
|
T_Damage(trace_ent, self, self, 5000);
|
|
}
|
|
|
|
};
|
|
|
|
void() ProximityAttack =
|
|
{
|
|
local vector vect;
|
|
local float dist;
|
|
local entity ent, oself;
|
|
|
|
if (other == world) {
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
if (other != self.enemy)
|
|
return;
|
|
|
|
ent = self.enemy;
|
|
|
|
// oself = self;
|
|
// self = self.owner;
|
|
|
|
vect = normalize(ent.origin - self.oldorigin);
|
|
dist = vlen(ent.origin - self.oldorigin);
|
|
|
|
if (dist > 200)
|
|
dist = 200;
|
|
|
|
if ((ent.classname != "apocalypse_small") && (ent.classname != "xmen_sinister"))
|
|
ent.velocity = ent.velocity + vect * (200 - dist) + '0 0 180';
|
|
|
|
ent.flags = ent.flags - (ent.flags & FL_ONGROUND);
|
|
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
|
|
WriteCoord (MSG_BROADCAST, ent.origin_x);
|
|
WriteCoord (MSG_BROADCAST, ent.origin_y);
|
|
WriteCoord (MSG_BROADCAST, ent.origin_z);
|
|
|
|
SpawnBlood (ent.origin, '0 0 0', 20);
|
|
|
|
if ((ent.classname == "xmen_sinister") || (ent.classname == "apocalypse_small"))
|
|
self.prox_power = self.prox_power / 5;
|
|
|
|
T_Damage(ent, self, self.owner, ent.start_health * (self.prox_power / 100) + 10);
|
|
|
|
// self = oself;
|
|
remove(self);
|
|
};
|
|
|
|
void() ProximityThink =
|
|
{
|
|
// remove if player is dead
|
|
if ((self.owner.health <= 0) || (self.modelindex == index_skeleton) || (intermission_running)) {
|
|
self.owner.prox_ent = world;
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
if (self.owner.last_prox_think < (time - 5)) {
|
|
self.owner.prox_ent = world;
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
self.frame = self.frame + 1;
|
|
if (self.frame > 5)
|
|
self.frame = 0;
|
|
|
|
if (self.last_flame_sound < (time - 0.75)) {
|
|
if (random() < 0.5)
|
|
sound(self, CHAN_AUTO, "weapons/prox1.wav", self.owner.prox_power / 100, ATTN_NORM);
|
|
else
|
|
sound(self, CHAN_AUTO, "weapons/prox2.wav", self.owner.prox_power / 100, ATTN_NORM);
|
|
|
|
self.last_flame_sound = time;
|
|
}
|
|
|
|
if (self.last_flame < (time - 0.05)) { // increase power
|
|
if ((self.owner.currentammo > 0) && (self.owner.prox_power < 100)) {
|
|
self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1;
|
|
self.owner.prox_power = self.owner.prox_power + 1;
|
|
|
|
if ((self.owner.currentammo > 0) && (self.owner.prox_power < 100)) {
|
|
self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1;
|
|
self.owner.prox_power = self.owner.prox_power + 1;
|
|
}
|
|
if ((self.owner.currentammo > 0) && (self.owner.prox_power < 100)) {
|
|
self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1;
|
|
self.owner.prox_power = self.owner.prox_power + 1;
|
|
}
|
|
|
|
// faster under rapid fire
|
|
if ((self.owner.x_flags & X_RAPID_FIRE) && (self.owner.currentammo > 0) && (self.owner.prox_power < 100)) {
|
|
self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1;
|
|
self.owner.prox_power = self.owner.prox_power + 1;
|
|
}
|
|
if ((self.owner.x_flags & X_RAPID_FIRE) && (self.owner.currentammo > 0) && (self.owner.prox_power < 100)) {
|
|
self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1;
|
|
self.owner.prox_power = self.owner.prox_power + 1;
|
|
}
|
|
|
|
if ((self.model == "progs/atom1.mdl") && (self.owner.prox_power > 40))
|
|
setmodel(self, "progs/atom2.mdl");
|
|
else if ((self.model == "progs/atom2.mdl") && (self.owner.prox_power > 70))
|
|
setmodel(self, "progs/atom3.mdl");
|
|
|
|
self.last_flame = time;
|
|
}
|
|
else if ((self.owner.prox_power >= 50) && (self.last_flame < (time - 3))) {
|
|
T_Damage(self.owner, world, world, 2);
|
|
self.last_flame = time - 2; // next hurt after 1 seconds only
|
|
}
|
|
}
|
|
|
|
if (self.movetype != MOVETYPE_BOUNCE) {
|
|
// align with owner
|
|
makevectors(self.owner.v_angle);
|
|
setorigin(self, self.owner.origin + v_forward * 24 + '0 0 22');
|
|
}
|
|
|
|
self.nextthink = time + 0.01;
|
|
};
|
|
|
|
void() StartProximity =
|
|
{
|
|
local entity prox;
|
|
|
|
if (self.prox_ent != world) {
|
|
remove(self.prox_ent);
|
|
self.prox_ent = world;
|
|
}
|
|
|
|
prox = spawn();
|
|
self.prox_ent = prox;
|
|
prox.classname = "proximity_ball";
|
|
prox.owner = self;
|
|
prox.spawn_time = time;
|
|
|
|
prox.movetype = MOVETYPE_FLY;
|
|
prox.avelocity = '100 0 0' * random() + '0 100 0' * random() + '0 0 100' * random() - '50 50 50';
|
|
|
|
setmodel(prox, "progs/atom1.mdl");
|
|
|
|
self.last_prox_think = time;
|
|
|
|
prox.think = ProximityThink;
|
|
self = prox;
|
|
ProximityThink();
|
|
self = self.owner;
|
|
};
|
|
|
|
void(entity targ) SpawnProxMissile =
|
|
{
|
|
local entity missile;
|
|
local vector dir, vect;
|
|
|
|
missile = spawn ();
|
|
missile.classname = "prox_missile";
|
|
missile.attack_finished = time + 3;
|
|
missile.owner = self.owner;
|
|
missile.oldorigin = self.origin;
|
|
missile.movetype = MOVETYPE_FLYMISSILE;
|
|
missile.solid = SOLID_BBOX;
|
|
|
|
missile.prox_power = self.owner.prox_power;
|
|
|
|
dir = normalize(targ.origin - self.origin);
|
|
|
|
dir = normalize('0 0 1' + dir * 5);
|
|
|
|
missile.enemy = targ;
|
|
|
|
missile.think = GuidedRocketStart;
|
|
missile.nextthink = time + 0.05;
|
|
|
|
missile.old_velocity = dir;
|
|
|
|
// set missile speed
|
|
|
|
missile.velocity = dir;
|
|
missile.velocity = missile.velocity * 750;
|
|
missile.angles = vectoangles(missile.velocity);
|
|
|
|
missile.touch = ProximityAttack;
|
|
|
|
setmodel (missile, "progs/atomshot.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
vect = normalize(self.velocity);
|
|
setorigin (missile, self.origin - vect * 8);
|
|
};
|
|
|
|
void() ProximityTouch =
|
|
{
|
|
local entity trav, expthink;
|
|
local float num;
|
|
|
|
if (other == self.owner)
|
|
return;
|
|
|
|
sound(self, CHAN_ITEM, "items/damage2.wav", 1, ATTN_NORM);
|
|
// sound(self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM);
|
|
|
|
num = rint(6 * (self.prox_power / 100)) + 2;
|
|
|
|
trav = findradius(self.origin, 800);
|
|
while ((trav != world) && (num > 0)) {
|
|
if ((trav.takedamage) && (trav != self.owner)) {
|
|
// check visibility
|
|
traceline(self.origin, trav.origin, TRUE, trav);
|
|
if ((trace_fraction == 1) || (trace_ent == trav)) {
|
|
|
|
if (((trav.classname != "xmen_sinister") || (self.x_flags & X_MEGA_HIT)) &&
|
|
(trav.classname != "xmen_apocalypse")) {
|
|
SpawnProxMissile(trav);
|
|
num = num - 1;
|
|
}
|
|
/*
|
|
expthink = spawn();
|
|
expthink.enemy = trav;
|
|
expthink.owner = self.owner;
|
|
expthink.prox_power = self.prox_power;
|
|
expthink.think = ProximityAttack;
|
|
expthink.nextthink = time + vlen(trav.origin - self.origin) / 400;
|
|
*/
|
|
// ProximityAttack(trav);
|
|
}
|
|
}
|
|
|
|
trav = trav.chain;
|
|
}
|
|
|
|
if (other.takedamage)
|
|
T_Damage(other, self, self, self.owner.prox_power);
|
|
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
|
|
BecomeExplosion ();
|
|
|
|
self.owner.prox_ent = world;
|
|
};
|
|
|
|
void() W_FireProximity =
|
|
{
|
|
local vector org;
|
|
local float cells;
|
|
local entity trav, expthink;
|
|
|
|
/*
|
|
if (self.ammo_cells < 1)
|
|
{
|
|
self.weapon = W_BestWeapon ();
|
|
W_SetCurrentAmmo ();
|
|
return;
|
|
}
|
|
|
|
if (self.ammo_cells > 50) {
|
|
cells = 50;
|
|
self.currentammo = self.ammo_cells = self.ammo_cells - 50;
|
|
}
|
|
else {
|
|
cells = self.ammo_cells;
|
|
self.currentammo = self.ammo_cells = 0;
|
|
}
|
|
*/
|
|
|
|
if (self.prox_ent == world) // nothing to throw
|
|
return;
|
|
|
|
// Throw the proxmity ball
|
|
self.prox_ent.solid = SOLID_TRIGGER;
|
|
self.prox_ent.movetype = MOVETYPE_FLYMISSILE;
|
|
setsize(self.prox_ent, '0 0 0', '0 0 0');
|
|
self.prox_ent.touch = ProximityTouch;
|
|
self.prox_ent.prox_power = self.prox_power;
|
|
self.prox_ent.think = SUB_Null;
|
|
|
|
makevectors(self.v_angle);
|
|
// self.prox_ent.velocity = self.velocity + (v_forward*2 + v_up*0.5) * 50 + '0 0 80';
|
|
self.prox_ent.velocity = v_forward * 750;
|
|
|
|
self.attack_finished = time + 2;
|
|
|
|
// stuffcmd(self, "bf\n");
|
|
|
|
sound(self, CHAN_ITEM, "cannon/takeoff.wav", 1, ATTN_NORM);
|
|
|
|
/*
|
|
sound(self, CHAN_WEAPON, "items/damage2.wav", 1, ATTN_NORM);
|
|
sound(self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM);
|
|
|
|
trav = findradius(self.origin, 800);
|
|
while (trav != world) {
|
|
if ((trav.takedamage) && (trav != self)) {
|
|
// check visibility
|
|
traceline(self.origin, trav.origin, TRUE, trav);
|
|
if ((trace_fraction == 1) || (trace_ent == trav)) {
|
|
expthink = spawn();
|
|
expthink.enemy = trav;
|
|
expthink.owner = self;
|
|
expthink.think = ProximityAttack;
|
|
expthink.nextthink = time + vlen(trav.origin - self.origin) / 400;
|
|
|
|
// ProximityAttack(trav);
|
|
}
|
|
}
|
|
|
|
trav = trav.chain;
|
|
}
|
|
*/
|
|
};
|
|
|
|
//=============================================================================
|
|
|
|
|
|
void() GrenadeExplode =
|
|
{
|
|
T_RadiusDamage (self, self.owner, 60, world);
|
|
|
|
/*
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
*/
|
|
if ((other.movetype) && (other.flags & FL_ONGROUND) && (other.classname != "xmen_sinister") && (other.classname != "apocalypse_small")) { // give some velocity
|
|
other.velocity = other.velocity + normalize(self.velocity) * 100 + '0 0 220';
|
|
other.flags = other.flags - (other.flags & FL_ONGROUND);
|
|
setorigin(other, other.origin + '0 0 1');
|
|
}
|
|
|
|
sound(self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
|
|
|
|
BecomeExplosion ();
|
|
};
|
|
|
|
void() GrenadeTouch =
|
|
{
|
|
if (other == self.owner)
|
|
return; // don't explode on owner
|
|
|
|
if ((other.classname == "xmen_phoenix") &&
|
|
(other.flags & FL_GODMODE))
|
|
return;
|
|
|
|
if ((other.takedamage == DAMAGE_AIM) && !(other.x_flags & X_ANGEL_DEFENSE))
|
|
{
|
|
GrenadeExplode();
|
|
return;
|
|
}
|
|
|
|
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
|
|
if (self.velocity == '0 0 0')
|
|
self.avelocity = '0 0 0';
|
|
};
|
|
|
|
/*
|
|
================
|
|
W_FireGrenade
|
|
================
|
|
*/
|
|
void() W_FireGrenade =
|
|
{
|
|
local entity missile, mpuff, phoenix;
|
|
|
|
if (self.ammo_rockets > 0)
|
|
self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
|
|
|
|
sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
|
|
|
|
self.punchangle_x = -2;
|
|
|
|
missile = spawn ();
|
|
missile.owner = self;
|
|
missile.movetype = MOVETYPE_BOUNCE;
|
|
missile.solid = SOLID_BBOX;
|
|
missile.classname = "orb";
|
|
|
|
// set missile speed
|
|
|
|
makevectors (self.v_angle);
|
|
|
|
if (self.v_angle_x)
|
|
missile.velocity = v_forward*900 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
|
|
else
|
|
{
|
|
missile.velocity = aim(self, 10000);
|
|
missile.velocity = missile.velocity * 900;
|
|
missile.velocity_z = 200;
|
|
}
|
|
|
|
missile.avelocity = '300 300 300';
|
|
|
|
missile.angles = vectoangles(missile.velocity);
|
|
|
|
missile.touch = GrenadeTouch;
|
|
|
|
// set missile duration
|
|
missile.nextthink = time + 2.5;
|
|
missile.think = GrenadeExplode;
|
|
|
|
setmodel (missile, "progs/orb1.mdl");
|
|
setsize (missile, '0 0 0', '0 0 0');
|
|
setorigin (missile, self.origin + v_right * 6 + v_forward * 16);
|
|
|
|
missile.old_velocity = missile.velocity;
|
|
|
|
// check for Pheonix defence
|
|
phoenix = find(world, classname, "xmen_phoenix");
|
|
while (phoenix != world) {
|
|
if (phoenix.enemy == self)
|
|
phoenix.guard_flag = TRUE;
|
|
|
|
phoenix = find(phoenix, classname, "xmen_phoenix");
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//=============================================================================
|
|
|
|
void() spike_touch;
|
|
void() superspike_touch;
|
|
|
|
|
|
/*
|
|
===============
|
|
launch_spike
|
|
|
|
Used for both the player and the ogre
|
|
===============
|
|
*/
|
|
void(vector org, vector dir) launch_spike =
|
|
{
|
|
newmis = spawn ();
|
|
newmis.owner = self;
|
|
newmis.movetype = MOVETYPE_FLYMISSILE;
|
|
newmis.solid = SOLID_BBOX;
|
|
|
|
newmis.angles = vectoangles(dir);
|
|
|
|
newmis.touch = spike_touch;
|
|
newmis.classname = "spike";
|
|
newmis.think = SUB_Remove;
|
|
newmis.nextthink = time + 6;
|
|
setmodel (newmis, "progs/spike.mdl");
|
|
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
|
|
setorigin (newmis, org);
|
|
|
|
newmis.velocity = dir * 1000;
|
|
};
|
|
|
|
void(float ox) W_FireSuperSpikes =
|
|
{
|
|
local vector dir;
|
|
local entity old;
|
|
local string sample;
|
|
local float shells;
|
|
|
|
sample = "weapons/chnfire5.wav";
|
|
|
|
if (self.last_weapon_channel != CHAN_WEAPON) {
|
|
sound (self, CHAN_WEAPON, sample, 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_WEAPON;
|
|
} else {
|
|
sound (self, CHAN_ITEM, sample, 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_ITEM;
|
|
}
|
|
|
|
self.attack_finished = time + 0.2;
|
|
|
|
if (random() < 0.5)
|
|
shells = 1;
|
|
else
|
|
shells = 2;
|
|
|
|
dir = aim (self, 100000);
|
|
|
|
if (self.ammo_shells <= shells) {
|
|
self.currentammo = self.ammo_shells = 0;
|
|
}
|
|
else {
|
|
self.currentammo = self.ammo_shells = self.ammo_shells - shells;
|
|
}
|
|
|
|
FireBullets (shells, dir, '0.04 0.04 0');
|
|
|
|
/*
|
|
self.currentammo = self.ammo_shells = self.ammo_shells - 1;
|
|
dir = aim (self, 1000);
|
|
launch_spike (self.origin + '0 0 16' + ox * v_right, dir);
|
|
newmis.touch = superspike_touch;
|
|
setmodel (newmis, "progs/s_spike.mdl");
|
|
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
|
|
*/
|
|
self.punchangle_x = -2;
|
|
};
|
|
|
|
void(float ox) W_FireSpikes =
|
|
{
|
|
local vector dir;
|
|
local entity old;
|
|
|
|
makevectors (self.v_angle);
|
|
|
|
if (self.weapon == IT_SHOTGUN)
|
|
{
|
|
W_FireSuperSpikes ();
|
|
return;
|
|
}
|
|
|
|
if (self.ammo_nails < 1)
|
|
{
|
|
self.weapon = W_BestWeapon ();
|
|
W_SetCurrentAmmo ();
|
|
return;
|
|
}
|
|
|
|
sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
|
|
self.attack_finished = time + 0.2;
|
|
self.currentammo = self.ammo_nails = self.ammo_nails - 1;
|
|
dir = aim (self, 1000);
|
|
launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
|
|
|
|
self.punchangle_x = -2;
|
|
};
|
|
|
|
|
|
/*
|
|
===============
|
|
Lazer Gun stuff
|
|
===============
|
|
*/
|
|
void() Flameball_Touch =
|
|
{
|
|
local vector org;
|
|
|
|
if (other == self.owner)
|
|
return; // don't explode on owner
|
|
|
|
if (pointcontents(self.origin) == CONTENT_SKY)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
// sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC);
|
|
org = self.origin - 8*normalize(self.velocity);
|
|
if ((other.health) && (other.classname != "xmen_bishop"))
|
|
{
|
|
SpawnBlood (org, self.velocity*0.2, 12);
|
|
T_Damage (other, self, self.owner, 12);
|
|
}
|
|
else
|
|
{
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
|
|
WriteCoord (MSG_BROADCAST, org_x);
|
|
WriteCoord (MSG_BROADCAST, org_y);
|
|
WriteCoord (MSG_BROADCAST, org_z);
|
|
}
|
|
|
|
self.origin = self.origin - 8*normalize(self.velocity);
|
|
|
|
BecomeExplosion ();
|
|
|
|
};
|
|
|
|
|
|
void() FlameballThink =
|
|
{
|
|
self.angles_z = (random() * 360) - 180;
|
|
|
|
if (self.spawn_time < (time - 6)) {
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
self.nextthink = time + 0.1;
|
|
};
|
|
|
|
void(vector org, vector dir) Launch_Flameball =
|
|
{
|
|
newmis = spawn ();
|
|
newmis.owner = self;
|
|
newmis.movetype = MOVETYPE_FLYMISSILE;
|
|
newmis.solid = SOLID_BBOX;
|
|
|
|
newmis.angles = vectoangles(dir);
|
|
|
|
newmis.touch = Flameball_Touch;
|
|
newmis.classname = "flameball";
|
|
newmis.think = FlameballThink;
|
|
newmis.nextthink = time + 0.1;
|
|
setmodel (newmis, "progs/flamball.mdl");
|
|
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
|
|
setorigin (newmis, org);
|
|
newmis.spawn_time = time;
|
|
newmis.angles_z = (random() * 360) - 180;
|
|
|
|
newmis.velocity = dir * 1500;
|
|
};
|
|
|
|
|
|
|
|
// X-Men: fires a laser projectile
|
|
void(float ox) W_FireFlameball =
|
|
{
|
|
local vector dir;
|
|
local entity old;
|
|
local string sample;
|
|
|
|
makevectors (self.v_angle);
|
|
|
|
sample = "weapons/f_start.wav";
|
|
|
|
if (self.last_weapon_channel != CHAN_WEAPON) {
|
|
sound (self, CHAN_WEAPON, sample, 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_WEAPON;
|
|
} else {
|
|
sound (self, CHAN_ITEM, sample, 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_ITEM;
|
|
}
|
|
|
|
if (self.ammo_nails < 1)
|
|
{
|
|
self.weapon = W_BestWeapon ();
|
|
W_SetCurrentAmmo ();
|
|
return;
|
|
}
|
|
|
|
// sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM);
|
|
self.attack_finished = time + 0.2;
|
|
self.currentammo = self.ammo_nails = self.ammo_nails - 1;
|
|
dir = v_forward;
|
|
Launch_Flameball (self.origin + '0 0 16' + v_right*4, dir);
|
|
|
|
self.punchangle_x = -2;
|
|
};
|
|
|
|
|
|
.float hit_z;
|
|
void() spike_touch =
|
|
{
|
|
local float rand, damg;
|
|
local vector vect;
|
|
|
|
if ((other == self.owner) || (other.owner == self.owner))
|
|
return;
|
|
|
|
if (other.solid == SOLID_TRIGGER)
|
|
return; // trigger field, do nothing
|
|
|
|
if (pointcontents(self.origin) == CONTENT_SKY)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
// hit something that bleeds
|
|
if (other.takedamage)
|
|
{
|
|
if (!self.dmg)
|
|
damg = 9;
|
|
else
|
|
damg = self.dmg;
|
|
|
|
spawn_touchblood (damg);
|
|
T_Damage (other, self, self.owner, damg);
|
|
|
|
remove(self);
|
|
return;
|
|
}
|
|
else if (self.classname == "angel_dart") {
|
|
vect = normalize(self.velocity);
|
|
setorigin(self, self.origin + vect*2);
|
|
|
|
self.velocity = '0 0 0';
|
|
self.solid = SOLID_NOT;
|
|
self.movetype = MOVETYPE_NONE;
|
|
|
|
self.think = SUB_Remove;
|
|
self.nextthink = time + 5;
|
|
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_SPIKE);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
|
|
return;
|
|
}
|
|
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
|
|
if (self.classname == "wizspike")
|
|
WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
|
|
else if (self.classname == "gambit_card")
|
|
WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
|
|
else
|
|
WriteByte (MSG_BROADCAST, TE_SPIKE);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
|
|
remove(self);
|
|
|
|
};
|
|
|
|
void() superspike_touch =
|
|
{
|
|
local float rand;
|
|
if (other == self.owner)
|
|
return;
|
|
|
|
if (other.solid == SOLID_TRIGGER)
|
|
return; // trigger field, do nothing
|
|
|
|
if (pointcontents(self.origin) == CONTENT_SKY)
|
|
{
|
|
remove(self);
|
|
return;
|
|
}
|
|
|
|
// hit something that bleeds
|
|
if (other.takedamage)
|
|
{
|
|
spawn_touchblood (18);
|
|
T_Damage (other, self, self.owner, 18);
|
|
}
|
|
else
|
|
{
|
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
|
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
}
|
|
|
|
remove(self);
|
|
|
|
};
|
|
|
|
/*
|
|
================
|
|
W_FireFlameThrower
|
|
================
|
|
*/
|
|
|
|
void(float num_bubbles) DeathBubbles;
|
|
void() W_FireFlameThrower =
|
|
{
|
|
local string sample;
|
|
|
|
if (self.classname == "player") {
|
|
if (self.ammo_nails < 1)
|
|
{
|
|
self.weapon = W_BestWeapon ();
|
|
W_SetCurrentAmmo ();
|
|
return;
|
|
}
|
|
|
|
if (self.ammo_nails < 4)
|
|
self.ammo_nails = 0;
|
|
else
|
|
self.ammo_nails = self.ammo_nails - 4;
|
|
|
|
self.currentammo = self.ammo_nails;
|
|
|
|
if (self.waterlevel >= 3) { // can't fire while underwater
|
|
self.flags = self.flags - (self.flags & FL_FLAMEON);
|
|
self.water_flame_flag = TRUE;
|
|
DeathBubbles(1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
sample = "weapons/flame.wav";
|
|
|
|
if (self.last_flame_sound < (time - SNDLEN_FLAME)) {
|
|
if (self.last_weapon_channel != CHAN_WEAPON) {
|
|
sound (self, CHAN_WEAPON, sample, 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_WEAPON;
|
|
} else {
|
|
sound (self, CHAN_ITEM, sample, 1, ATTN_NORM);
|
|
self.last_weapon_channel = CHAN_ITEM;
|
|
}
|
|
|
|
self.last_flame_sound = time + (random() * 0.2) - 0.05;
|
|
}
|
|
|
|
if (!(self.flags & FL_FLAMEON))
|
|
{
|
|
//bprint("starting flame..\n");
|
|
setorigin(self.flame_ent1, self.origin + v_forward * 16);
|
|
setorigin(self.flame_ent2, self.origin + v_forward * 16);
|
|
setorigin(self.flame_ent3, self.origin + v_forward * 96);
|
|
self.flame_ent1.nextthink = time + 0.05;
|
|
self.flame_ent1.speed = 0;
|
|
self.flame_ent2.speed = 0;
|
|
self.flame_ent3.speed = 0;
|
|
|
|
setmodel(self.flame_ent1, "progs/fl_th1.mdl");
|
|
setmodel(self.flame_ent2, "progs/null.spr");
|
|
setmodel(self.flame_ent3, "progs/fl_th5.mdl");
|
|
}
|
|
|
|
if (self.water_flame_flag) {
|
|
self.flags = self.flags | FL_FLAMEON;
|
|
self.water_flame_flag = FALSE;
|
|
}
|
|
|
|
self.last_flame = time;
|
|
};
|
|
|
|
void(entity ent, vector pos, float dist) movetopos =
|
|
{
|
|
local vector vect;
|
|
|
|
if (vlen(ent.origin - pos) > dist) {
|
|
vect = normalize(pos - ent.origin);
|
|
setorigin(ent, ent.origin + vect * dist);
|
|
}
|
|
else
|
|
{
|
|
setorigin(ent, pos);
|
|
}
|
|
};
|
|
|
|
void(vector p1, vector p2) FlameParticles =
|
|
{
|
|
local float rcol, rnd;
|
|
local vector vect, avect, rvect, org, vel;
|
|
|
|
// random color between 228 - 233
|
|
rnd = random();
|
|
rcol = 228 + floor(rnd * 2);
|
|
|
|
// do vector stuff
|
|
vect = normalize(p2 - p1);
|
|
avect = vectoangles(vect);
|
|
avect_x = -1 * vect_x;
|
|
|
|
makevectors(avect);
|
|
|
|
rvect = ('1 0 0' * random()) + ('0 1 0' * random()) + ('0 0 1' * random()) - '0.5 0.5 0.5';
|
|
|
|
org = p1 +
|
|
v_forward * 32 +
|
|
v_forward * rnd * FLAME_DIST * 0.5;
|
|
|
|
vel = normalize(v_forward + (rvect * 0.3) + '0 0 0.2') * 20;
|
|
|
|
particle( org, v_forward * 10, 235, 20);
|
|
particle( org, vel, rcol, 50);
|
|
|
|
// flame_ent_think() requires the following line..
|
|
makevectors(self.owner.v_angle);
|
|
};
|
|
|
|
void() flame_ent_think =
|
|
{
|
|
local entity ent, ent_parent;
|
|
local vector vect, ideal_pnt, ofs, oldangles;
|
|
local float this_dist, this_speed, dist_from, dist1, dist2, short_flag;
|
|
local entity ent_burn;
|
|
|
|
short_flag = FALSE;
|
|
|
|
// set flame distance
|
|
if (!(self.owner.flags & FL_FLAMEON)) {
|
|
//bprint("stopping flame..\n");
|
|
// if ((vlen(self.origin - self.owner.origin) < 32) ||
|
|
// (self.owner.last_flame < (time - 1))) { // flame has run out
|
|
|
|
setmodel(self.owner.flame_ent1, string_null);
|
|
setmodel(self.owner.flame_ent2, string_null);
|
|
setmodel(self.owner.flame_ent3, string_null);
|
|
|
|
self.owner.flame_ent1.effects = 0;
|
|
self.owner.flame_ent2.effects = 0;
|
|
self.owner.flame_ent3.effects = 0;
|
|
|
|
self.nextthink = -1;
|
|
return;
|
|
// }
|
|
|
|
this_dist = -2 * FLAME_DIST;
|
|
|
|
self.speed = self.speed - (FLAME_ENT_SPEED * frametime * 0.5);
|
|
if (self.speed < 0)
|
|
self.speed = 0;
|
|
}
|
|
else {
|
|
this_dist = FLAME_DIST;
|
|
}
|
|
|
|
self.nextthink = time + 0.05;
|
|
|
|
ent_burn = world;
|
|
makevectors(self.owner.v_angle);
|
|
|
|
ofs = v_forward * 32 + v_right * 10 + '0 0 36' - v_up * 28;
|
|
if (self.owner.character == CHAR_STORM)
|
|
ofs_z = ofs_z + STORM_VOFS_Z;
|
|
|
|
// move 1st junction to ideal position ****************************************************
|
|
ent = self;
|
|
ent_parent = self.owner;
|
|
traceline(ent_parent.origin + ofs - v_forward * 32, ent_parent.origin + ofs + v_forward * this_dist * 0.5, FALSE, self.owner);
|
|
|
|
dist_from = vlen(ent.origin - trace_endpos);
|
|
|
|
// ent.angles = vectoangles(v_forward);
|
|
// ent.angles_z = (360 * random()) - 180;
|
|
ent.angles = self.owner.v_angle;
|
|
ent.angles_x = -1 * ent.angles_x;
|
|
ent.angles_z = random() * 360 - 180;
|
|
|
|
movetopos(ent, trace_endpos, FLAME_ENT_SPEED * frametime);
|
|
|
|
/*
|
|
FlameParticles(ent.owner.origin + ofs * 2 - '0 0 4', ent.origin);
|
|
FlameParticles(ent.owner.origin + ofs * 2 - '0 0 4', ent.origin);
|
|
FlameParticles(ent.owner.origin + ofs * 2 - '0 0 4', ent.origin);
|
|
*/
|
|
|
|
// fill with flame bits
|
|
// FillBetweenPoints(ent_parent.origin + ofs, ent.origin, "progs/fl_th1.mdl", '0 0 0', 0.07);
|
|
// ent.effects = ent.effects | EF_MUZZLEFLASH;
|
|
if (ent.speed < FLAME_DIST) {
|
|
ent.speed = ent.speed + (FLAME_ENT_SPEED * frametime * 0.5);
|
|
if (ent.speed > FLAME_DIST)
|
|
ent.speed = FLAME_DIST;
|
|
}
|
|
if (trace_fraction < 1) {
|
|
setorigin(self.owner.flame_ent2, ent.origin);
|
|
self.owner.flame_ent2.speed = 0;
|
|
setorigin(self.owner.flame_ent3, ent.origin);
|
|
self.owner.flame_ent3.speed = 0;
|
|
|
|
if ((trace_ent != world) && (trace_ent.takedamage)) {
|
|
ent_burn = trace_ent;
|
|
}
|
|
|
|
short_flag = TRUE;
|
|
}
|
|
|
|
// T_RadiusDamage(ent, self.owner, 10, self.owner);
|
|
|
|
// move 2nd junction to ideal position ****************************************************
|
|
ent_parent = self.owner.flame_ent1;
|
|
ent = self.owner.flame_ent2;
|
|
traceline(ent_parent.origin - v_forward * 2, ent_parent.origin + v_forward * this_dist, FALSE, self.owner);
|
|
|
|
dist_from = vlen(ent.origin - trace_endpos);
|
|
|
|
if (dist_from < 4)
|
|
ent.angles = vectoangles('0 0 1');
|
|
else {
|
|
vect = normalize(ent.origin - trace_endpos);
|
|
ent.angles = vectoangles(vect);
|
|
}
|
|
|
|
ent.angles_z = (360 * random()) - 180;
|
|
|
|
this_speed = FLAME_ENT_SPEED * (dist_from / 64);
|
|
|
|
if (this_speed > (FLAME_ENT_SPEED * 2))
|
|
this_speed = FLAME_ENT_SPEED*2;
|
|
|
|
movetopos(ent, trace_endpos, dist_from / 2); //this_speed * frametime);
|
|
// movetopos(ent, trace_endpos, this_speed * frametime);
|
|
|
|
if (trace_fraction == 1) {
|
|
vect = normalize(ent.origin - ent_parent.origin);
|
|
setorigin(ent, ent_parent.origin + (vect * ent.speed));
|
|
}
|
|
|
|
// FlameParticles(ent.owner.origin, ent.origin);
|
|
|
|
// fill with flame bits
|
|
dist_from = vlen(ent.origin - ent_parent.origin);
|
|
if (dist_from > 32)
|
|
FillBetweenPoints(ent_parent.origin, ent.origin - v_forward * 30, "progs/fl_th2.mdl", '0 0 0', 0.07);
|
|
ent.effects = ent.effects | EF_DIMLIGHT;
|
|
if (ent.speed < FLAME_DIST) {
|
|
ent.speed = ent.speed + (FLAME_ENT_SPEED * frametime * 0.5);
|
|
if (ent.speed > FLAME_DIST * 0.75)
|
|
ent.speed = FLAME_DIST * 0.75;
|
|
}
|
|
|
|
if (trace_fraction < 1) {
|
|
setorigin(self.owner.flame_ent3, ent.origin);
|
|
self.owner.flame_ent3.speed = 0;
|
|
|
|
if ((trace_ent != world) && (trace_ent.takedamage)) {
|
|
ent_burn = trace_ent;
|
|
}
|
|
|
|
short_flag = TRUE;
|
|
}
|
|
|
|
if (deathmatch)
|
|
T_RadiusDamage(ent, self.owner, 15, self.owner);
|
|
else
|
|
T_RadiusDamage(ent, self.owner, 10, self.owner);
|
|
|
|
|
|
// move 3rd junction to ideal position ****************************************************
|
|
v_forward = vect;
|
|
|
|
ent_parent = self.owner.flame_ent2;
|
|
ent = self.owner.flame_ent3;
|
|
ideal_pnt = ent_parent.origin + v_forward * this_dist * 0.75;
|
|
traceline(ent_parent.origin - v_forward * 2, ideal_pnt, FALSE, self.owner);
|
|
|
|
dist_from = vlen(ent.origin - trace_endpos);
|
|
|
|
// if (dist_from < 4)
|
|
// ent.angles = vectoangles('0 0 1');
|
|
// else {
|
|
// vect = normalize(ent.origin - trace_endpos);
|
|
// ent.angles = vectoangles(vect);
|
|
// }
|
|
|
|
// ent.angles_z = (360 * random()) - 180;
|
|
|
|
ent.frame = random() * 5.9;
|
|
ent.frame = floor(ent.frame);
|
|
|
|
|
|
dist_from = vlen(ent.origin - ideal_pnt); //trace_endpos);
|
|
this_speed = FLAME_ENT_SPEED * (dist_from / 256);
|
|
|
|
if (this_speed > (FLAME_ENT_SPEED * 2))
|
|
this_speed = FLAME_ENT_SPEED*2;
|
|
|
|
this_speed = this_speed * 3;
|
|
|
|
ent.oldorigin = ent.origin;
|
|
movetopos(ent, trace_endpos, dist_from / 3); //this_speed * frametime);
|
|
|
|
if (vlen(ent.origin - ent_parent.origin) > this_dist * 0.75) {
|
|
vect = normalize(ent.origin - ent_parent.origin);
|
|
setorigin(ent, ent_parent.origin + (vect * this_dist * 0.75));
|
|
}
|
|
|
|
oldangles = ent.angles;
|
|
if ((trace_fraction == 1) && (!short_flag)) {
|
|
vect = normalize(ent.origin - ent_parent.origin);
|
|
ent.angles = vectoangles(vect);
|
|
if (ent.model != "progs/fl_th5.mdl")
|
|
setmodel(ent, "progs/fl_th5.mdl");
|
|
}
|
|
else {
|
|
vect = normalize(ent.origin - self.owner.origin);
|
|
ent.angles = vectoangles(vect);
|
|
// ent.angles_x = ent.angles_x + 45;
|
|
if (ent.model != "progs/fl_th6.mdl")
|
|
setmodel(ent, "progs/fl_th6.mdl");
|
|
}
|
|
|
|
// ent.angles_x = -1 * ent.angles_x;
|
|
|
|
// calculate Z rotation to match "sway" movement
|
|
makevectors(ent.angles);
|
|
vect = ent.origin - ent.oldorigin;
|
|
dist1 = vlen(vect + v_right);
|
|
dist2 = vlen(vect - v_right);
|
|
if ((!short_flag) && (vlen(vect) > 4)) {
|
|
if ((dist1 - dist2) > 0) { // moving towards RIGHT
|
|
ent.angles_z = MoveToAngle(oldangles_z, 320, 500);
|
|
}
|
|
else if ((dist1 - dist2) < 0) { // moving towards LEFT
|
|
ent.angles_z = MoveToAngle(oldangles_z, 40, 500);
|
|
}
|
|
}
|
|
else { // move towards 0
|
|
ent.angles_z = MoveToAngle(oldangles_z, 0, 500);
|
|
}
|
|
|
|
vect = normalize(ent.origin - ent.owner.origin);
|
|
dist_from = vlen(vect);
|
|
|
|
/*
|
|
if ((vlen(ent.origin - self.owner.origin) > FLAME_DIST) || (trace_fraction < 1)) {
|
|
// if (trace_fraction == 1) {
|
|
// vect = normalize(ent.origin - ent_parent.origin);
|
|
// setorigin(ent, ent_parent.origin + (vect * ent.speed));
|
|
// }
|
|
|
|
if (ent.model != "progs/fl_th3.mdl")
|
|
setmodel(ent, "progs/fl_th3.mdl");
|
|
}
|
|
else {
|
|
if (ent.model != "progs/fl_th2.mdl")
|
|
setmodel(ent, "progs/fl_th2.mdl");
|
|
}
|
|
*/
|
|
// FlameParticles(ent.owner.origin, ent.origin);
|
|
|
|
// fill with flame bits
|
|
// FillBetweenPoints(ent_parent.origin + vect * (dist_from / 2), ent.origin, "progs/fl_th3.mdl", '45 0 0', 0.07);
|
|
ent.effects = ent.effects | EF_DIMLIGHT;
|
|
if (ent.speed < FLAME_DIST) {
|
|
ent.speed = ent.speed + (FLAME_ENT_SPEED * frametime * 0.5);
|
|
if (ent.speed > FLAME_DIST * 0.5)
|
|
ent.speed = FLAME_DIST * 0.5;
|
|
}
|
|
|
|
if ((trace_ent != world) && (trace_ent.takedamage)) {
|
|
ent_burn = trace_ent;
|
|
}
|
|
|
|
if (deathmatch)
|
|
T_RadiusDamage(ent, self.owner, 20, self.owner);
|
|
else
|
|
T_RadiusDamage(ent, self.owner, 13, self.owner);
|
|
|
|
if (ent_burn != world && deathmatch) {
|
|
T_Damage(trace_ent, self.owner, self.owner, 8);
|
|
}
|
|
|
|
};
|
|
|
|
void() SetSpecialWeaponModel =
|
|
{
|
|
if (self.character == CHAR_WOLVERINE) {
|
|
self.weaponmodel = "progs/v_wol.mdl";
|
|
}
|
|
else if (self.character == CHAR_STORM) {
|
|
self.weaponmodel = "progs/v_sto.mdl";
|
|
}
|
|
else if (self.character == CHAR_CYCLOPS) {
|
|
self.weaponmodel = "progs/v_cyc.mdl";
|
|
}
|
|
else if (self.character == CHAR_PSYLOCKE) {
|
|
self.weaponmodel = "progs/v_psy.mdl";
|
|
}
|
|
else if (self.character == CHAR_ANGEL) {
|
|
self.weaponmodel = "progs/v_ang.mdl";
|
|
}
|
|
else if (self.character == CHAR_BEAST) {
|
|
self.weaponmodel = "progs/v_bea.mdl";
|
|
}
|
|
else if (self.character == CHAR_GAMBIT) {
|
|
self.weaponmodel = "progs/v_gam.mdl";
|
|
}
|
|
else if (self.character == CHAR_ICEMAN) {
|
|
self.weaponmodel = "progs/v_ice.mdl";
|
|
}
|
|
else if (self.character == CHAR_BISHOP) {
|
|
self.weaponmodel = "progs/v_bis.mdl";
|
|
}
|
|
else if (self.character == CHAR_ROGUE) {
|
|
self.weaponmodel = "progs/v_rog.mdl";
|
|
}
|
|
else if (self.character == CHAR_CANNONBALL) {
|
|
self.weaponmodel = "progs/v_can.mdl";
|
|
}
|
|
else if (self.character == CHAR_PHOENIX) {
|
|
self.weaponmodel = "progs/v_pho.mdl";
|
|
}
|
|
else {
|
|
self.weaponmodel = "";
|
|
sprint(self, "ERROR: Unknown character setting\n");
|
|
}
|
|
};
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
PLAYER WEAPON USE
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
void() SpecialWeaponChange;
|
|
void() W_SetCurrentAmmo =
|
|
{
|
|
// player_run (); // get out of any weapon firing states
|
|
|
|
if (self.modelindex == index_skeleton)
|
|
return;
|
|
|
|
self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
|
|
|
|
if (self.weapon == IT_AXE)
|
|
{
|
|
self.currentammo = 0;
|
|
|
|
if (deathmatch || coop) {
|
|
SetSpecialWeaponModel();
|
|
}
|
|
else {
|
|
self.weaponmodel = "progs/v_xfist.mdl";
|
|
}
|
|
}
|
|
else if (self.weapon == IT_SHOTGUN)
|
|
{
|
|
self.currentammo = self.ammo_shells;
|
|
self.weaponmodel = "progs/v_xshot1.mdl";
|
|
self.items = self.items | IT_SHELLS;
|
|
}
|
|
else if (self.weapon == IT_SUPER_SHOTGUN)
|
|
{
|
|
self.currentammo = self.ammo_shells;
|
|
self.weaponmodel = "progs/v_xchain.mdl";
|
|
self.items = self.items | IT_SHELLS;
|
|
}
|
|
else if (self.weapon == IT_NAILGUN)
|
|
{
|
|
self.currentammo = self.ammo_nails;
|
|
self.weaponmodel = "progs/v_xfire1.mdl";
|
|
self.items = self.items | IT_NAILS;
|
|
}
|
|
else if (self.weapon == IT_SUPER_NAILGUN)
|
|
{
|
|
self.currentammo = self.ammo_nails;
|
|
self.weaponmodel = "progs/v_xflame.mdl";
|
|
self.items = self.items | IT_NAILS;
|
|
}
|
|
else if (self.weapon == IT_GRENADE_LAUNCHER)
|
|
{
|
|
self.currentammo = self.ammo_rockets;
|
|
self.weaponmodel = "progs/v_xorb.mdl";
|
|
self.items = self.items | IT_ROCKETS;
|
|
}
|
|
else if (self.weapon == IT_ROCKET_LAUNCHER)
|
|
{
|
|
self.currentammo = self.ammo_rockets;
|
|
self.weaponmodel = "progs/v_xrock.mdl";
|
|
self.items = self.items | IT_ROCKETS;
|
|
}
|
|
else if (self.weapon == IT_LIGHTNING)
|
|
{
|
|
self.currentammo = self.ammo_cells;
|
|
self.weaponmodel = "progs/v_xshock.mdl";
|
|
self.items = self.items | IT_CELLS;
|
|
}
|
|
else if (self.weapon == IT_SPECIAL_WEAPON)
|
|
{
|
|
self.currentammo = self.ammo_special;
|
|
self.weaponmodel = "progs/v_xmega.mdl";
|
|
self.items = self.items | IT_CELLS;
|
|
}
|
|
else
|
|
{
|
|
self.currentammo = 0;
|
|
self.weaponmodel = "";
|
|
}
|
|
};
|
|
|
|
float() W_BestWeapon =
|
|
{
|
|
local float it;
|
|
|
|
it = self.items;
|
|
|
|
if(self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
|
|
return IT_LIGHTNING;
|
|
else if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
|
|
return IT_ROCKET_LAUNCHER;
|
|
else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
|
|
return IT_GRENADE_LAUNCHER;
|
|
else if (self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
|
|
return IT_SUPER_NAILGUN;
|
|
else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
|
|
return IT_SUPER_SHOTGUN;
|
|
else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
|
|
return IT_NAILGUN;
|
|
else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
|
|
return IT_SHOTGUN;
|
|
|
|
return IT_AXE;
|
|
};
|
|
|
|
float() W_CheckNoAmmo =
|
|
{
|
|
local float best;
|
|
|
|
if (self.currentammo > 0)
|
|
return TRUE;
|
|
|
|
if (self.weapon == IT_AXE)
|
|
return TRUE;
|
|
|
|
// self.nextweapon = W_BestWeapon ();
|
|
|
|
// best = W_BestWeapon ();
|
|
// SetNewWeapon(best);
|
|
|
|
// W_SetCurrentAmmo ();
|
|
|
|
// drop the weapon down
|
|
return FALSE;
|
|
};
|
|
|
|
/*
|
|
============
|
|
W_Attack
|
|
|
|
An attack impulse can be triggered now
|
|
============
|
|
*/
|
|
void() player_att1;
|
|
void() player_laser1;
|
|
void() player_flame1;
|
|
void() player_prox1;
|
|
void() player_orb;
|
|
void() player_rocket1;
|
|
|
|
void() player_shotgun1;
|
|
void() player_chain1;
|
|
void() player_fist;
|
|
void() player_mega;
|
|
|
|
void() W_Attack =
|
|
{
|
|
local float r, best;
|
|
|
|
if (self.modelindex == index_skeleton)
|
|
return;
|
|
|
|
if (self.change_weapon_status) { // no firing during fading
|
|
// sprint(self, "can't fire, changing weapons\n");
|
|
return;
|
|
}
|
|
|
|
if (self.weapon_flags & W_RELOADING) {
|
|
// sprint(self, "can't fire, reloading\n");
|
|
return;
|
|
}
|
|
|
|
if (!W_CheckNoAmmo ()) {
|
|
best = W_BestWeapon ();
|
|
SetNewWeapon(best);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
if ((self.weapon == IT_NAILGUN) && (self.num_lasers >= 5))
|
|
return;
|
|
else if ((self.num_lasers > 0) && (self.weapon != IT_NAILGUN))
|
|
self.num_lasers = 0;
|
|
*/
|
|
|
|
makevectors (self.v_angle); // calculate forward angle for velocity
|
|
self.show_hostile = time + 1; // wake monsters up
|
|
|
|
if (self.weapon == IT_AXE)
|
|
{
|
|
if (deathmatch || coop) {
|
|
if ((!(self.weapon_flags & W_RELOADING)) &&
|
|
((self.character != CHAR_CANNONBALL) || (self.last_special2 < (time - 1.5)))) {
|
|
player_att1 ();
|
|
}
|
|
}
|
|
else {
|
|
player_fist();
|
|
}
|
|
|
|
// self.attack_finished = time + 0.5;
|
|
}
|
|
else if (self.weapon == IT_SHOTGUN)
|
|
{
|
|
if (self.think != player_shotgun1) {
|
|
self.weaponframe = 5;
|
|
player_shotgun1 ();
|
|
}
|
|
self.attack_finished = time + 0.3;
|
|
}
|
|
else if (self.weapon == IT_SUPER_SHOTGUN)
|
|
{
|
|
if (self.weaponframe > 11)
|
|
self.weaponframe = 6;
|
|
|
|
if (time > self.w_pausetime)
|
|
self.last_pausetime = 0;
|
|
|
|
player_chain1 ();
|
|
}
|
|
else if (self.weapon == IT_NAILGUN)
|
|
{
|
|
// self.weaponmodel = "progs/v_xlas2.mdl";
|
|
|
|
// player_nail1 ();
|
|
|
|
self.fire_reload_frames = 0;
|
|
player_laser1 ();
|
|
}
|
|
else if (self.weapon == IT_SUPER_NAILGUN)
|
|
{
|
|
player_flame1();
|
|
self.attack_finished = time + 0.1;
|
|
if (self.waterlevel < 3) { // can't fire while underwater
|
|
if (!(self.flags & FL_FLAMEON))
|
|
sound(self, CHAN_BODY, "weapons/f_start.wav", 1, ATTN_NORM);
|
|
|
|
self.flags = self.flags | FL_FLAMEON;
|
|
}
|
|
}
|
|
else if (self.weapon == IT_GRENADE_LAUNCHER)
|
|
{
|
|
player_orb();
|
|
// W_FireGrenade();
|
|
}
|
|
else if (self.weapon == IT_ROCKET_LAUNCHER)
|
|
{
|
|
player_rocket1();
|
|
// W_FireRocket();
|
|
W_FireGuidedRockets();
|
|
self.attack_finished = time + 1.6;
|
|
}
|
|
else if (self.weapon == IT_LIGHTNING)
|
|
{
|
|
// if (self.prox_ent != world)
|
|
// return;
|
|
|
|
player_prox1();
|
|
self.attack_finished = time + 0.2;
|
|
// sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
|
|
}
|
|
else if (self.weapon == IT_SPECIAL_WEAPON)
|
|
{
|
|
player_mega();
|
|
self.attack_finished = time + 0.2;
|
|
sound (self, CHAN_ITEM, "weapons/m_start.wav", 1, ATTN_NORM);
|
|
sound (self, CHAN_WEAPON, "weapons/mega.wav", 1, ATTN_NONE);
|
|
}
|
|
};
|
|
|
|
float(float wpn) GetLastMoveFrame =
|
|
{
|
|
if (wpn == IT_SHOTGUN) return 25;
|
|
if (wpn == IT_SUPER_SHOTGUN) return 12;
|
|
if (wpn == IT_NAILGUN) return 15;
|
|
if (wpn == IT_SUPER_NAILGUN) return 9;
|
|
if (wpn == IT_GRENADE_LAUNCHER) return 18;
|
|
if (wpn == IT_LIGHTNING) return 0;
|
|
if (wpn == IT_ROCKET_LAUNCHER) return 17;
|
|
if (wpn == IT_AXE)
|
|
if (deathmatch || coop)
|
|
return 0;
|
|
else
|
|
return 16;
|
|
|
|
return 0;
|
|
};
|
|
|
|
float(float wpn) GetFirstMoveFrame =
|
|
{
|
|
if (wpn == IT_SHOTGUN) return 30; // NOTE: frame 31 = frame 1
|
|
if (wpn == IT_SUPER_SHOTGUN) return 17;
|
|
if (wpn == IT_NAILGUN) return 20;
|
|
if (wpn == IT_SUPER_NAILGUN) return 15;
|
|
if (wpn == IT_GRENADE_LAUNCHER) return 23;
|
|
if (wpn == IT_LIGHTNING) return 4;
|
|
if (wpn == IT_ROCKET_LAUNCHER) return 23;
|
|
if (wpn == IT_AXE)
|
|
if (deathmatch || coop)
|
|
return 5;
|
|
else
|
|
return 22;
|
|
|
|
return 0;
|
|
};
|
|
|
|
// Return true if next weapon is on a different hand to the current weapon
|
|
float() ChangingHands =
|
|
{
|
|
if ((deathmatch || coop) && (self.nextweapon == IT_AXE) && (self.weapon != IT_AXE))
|
|
return TRUE;
|
|
|
|
if (self.nextweapon == IT_LIGHTNING)
|
|
return TRUE;
|
|
|
|
if (self.nextweapon == IT_SPECIAL_WEAPON)
|
|
return TRUE;
|
|
|
|
if ((self.nextweapon & (IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_AXE)) &&
|
|
(self.weapon & (IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER))) {
|
|
return TRUE;
|
|
}
|
|
|
|
if ((self.nextweapon & (IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER)) &&
|
|
(self.weapon & (IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_AXE))) {
|
|
return TRUE;
|
|
}
|
|
};
|
|
|
|
/*
|
|
=================
|
|
FADE WEAPON OUT
|
|
=================
|
|
*/
|
|
void() FadeWeaponOut =
|
|
{
|
|
local float newframe;
|
|
local string str;
|
|
|
|
if (self.weapon_flags & W_RELOADING)
|
|
return;
|
|
|
|
if (self.chasecam != world) { // change immediately
|
|
self.weapon = self.nextweapon;
|
|
if (self.weapon == IT_AXE)
|
|
SpecialWeaponChange();
|
|
W_SetCurrentAmmo ();
|
|
self.weaponframe = newframe;
|
|
self.change_weapon_status = CW_FADEIN;
|
|
}
|
|
|
|
self.last_fade = time;
|
|
|
|
//bprint("fade out\n");
|
|
if (self.weapon & (IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_AXE | IT_GRENADE_LAUNCHER)) {
|
|
self.weaponframe = self.weaponframe - 1;
|
|
|
|
if (self.weaponframe <= self.fadeout_endframe) {
|
|
if ((self.fadeout_endframe == 0) && (ChangingHands()) && (GetLastMoveFrame(self.weapon) > 0)) {
|
|
self.fadeout_endframe = GetLastMoveFrame(self.weapon);
|
|
self.weaponframe = GetFirstMoveFrame(self.weapon);
|
|
return;
|
|
}
|
|
|
|
// if we're still here then weapon must have completed fading out
|
|
if (ChangingHands()) {
|
|
newframe = GetLastMoveFrame(self.nextweapon);
|
|
self.fadein_endframe = GetFirstMoveFrame(self.nextweapon);
|
|
}
|
|
else {
|
|
newframe = 0;
|
|
self.fadein_endframe = 5; // all morphing animations end at frame 5
|
|
}
|
|
|
|
self.weapon = self.nextweapon;
|
|
if (self.weapon == IT_AXE)
|
|
SpecialWeaponChange();
|
|
W_SetCurrentAmmo ();
|
|
self.weaponframe = newframe;
|
|
self.change_weapon_status = CW_FADEIN;
|
|
}
|
|
}
|
|
else {
|
|
self.weaponframe = 0;
|
|
self.weapon = self.nextweapon;
|
|
if (self.weapon == IT_AXE)
|
|
SpecialWeaponChange();
|
|
W_SetCurrentAmmo ();
|
|
self.change_weapon_status = CW_FADEIN;
|
|
}
|
|
};
|
|
|
|
/*
|
|
=================
|
|
FADE WEAPON IN
|
|
=================
|
|
*/
|
|
void() FadeWeaponIn =
|
|
{
|
|
local string str;
|
|
|
|
if (self.chasecam != world) { // change immediately
|
|
self.weaponframe = self.weapon_idleframe;
|
|
self.change_weapon_status = CW_DONE;
|
|
return;
|
|
}
|
|
|
|
self.last_fade = time;
|
|
|
|
if (self.weapon & (IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN | IT_SUPER_NAILGUN | IT_AXE | IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER)) {
|
|
self.weaponframe = self.weaponframe + 1;
|
|
|
|
if (self.weaponframe >= self.fadein_endframe) {
|
|
if (self.fadein_endframe >= 10) { // weapon has entered the screen
|
|
self.fadein_endframe = self.weapon_idleframe;
|
|
self.weaponframe = 0;
|
|
}
|
|
else {
|
|
self.change_weapon_status = CW_DONE;
|
|
}
|
|
}
|
|
}
|
|
else if (self.weapon == IT_SPECIAL_WEAPON) {
|
|
self.weaponframe = self.weaponframe + 1;
|
|
|
|
if (self.weaponframe == 11) {
|
|
self.change_weapon_status = CW_DONE;
|
|
}
|
|
}
|
|
else {
|
|
self.weaponframe = self.weapon_idleframe;
|
|
self.change_weapon_status = CW_DONE;
|
|
}
|
|
};
|
|
|
|
// Starts the morphing towards the new weapon
|
|
void(float wpn) SetNewWeapon =
|
|
{
|
|
// if (wpn & IT_LIGHTNING) {
|
|
// return;
|
|
// }
|
|
if (deathmatch == DM_SPECIAL_POWERS) {
|
|
self.weapon_idleframe = 6;
|
|
return;
|
|
}
|
|
|
|
if ((self.think != player_run) && (self.think != player_stand1)) // only change if idle
|
|
return;
|
|
|
|
if (wpn == self.weapon)
|
|
return;
|
|
|
|
if ((self.weapon == IT_LIGHTNING) &&
|
|
(self.prox_ent != world))
|
|
return;
|
|
|
|
// make sure we start at the idle frame
|
|
self.weaponframe = self.weapon_idleframe;
|
|
|
|
if ((deathmatch || coop) && (wpn == IT_AXE)) {
|
|
self.weapon_idleframe = 6;
|
|
}
|
|
else {
|
|
self.weapon_idleframe = 5;
|
|
}
|
|
|
|
self.nextweapon = wpn;
|
|
self.change_weapon_status = CW_FADEOUT;
|
|
self.fadeout_endframe = 0;
|
|
FadeWeaponOut();
|
|
};
|
|
|
|
/*
|
|
============
|
|
W_ChangeWeapon
|
|
============
|
|
*/
|
|
void() W_ChangeWeapon =
|
|
{
|
|
local float it, am, fl, new_idle;
|
|
|
|
if (self.modelindex == index_skeleton)
|
|
return;
|
|
|
|
if ((deathmatch == DM_SPECIAL_POWERS) && (self.impulse != 1))
|
|
return;
|
|
|
|
it = self.items;
|
|
am = 0;
|
|
|
|
if (self.impulse == 1)
|
|
{
|
|
fl = IT_AXE;
|
|
new_idle = 6;
|
|
|
|
if ((deathmatch || coop) && (self.weapon == IT_AXE)) {
|
|
self.special_weapon = !self.special_weapon;
|
|
}
|
|
}
|
|
else if (self.impulse == 2)
|
|
{
|
|
fl = IT_SHOTGUN;
|
|
new_idle = 5;
|
|
if (self.ammo_shells < 2)
|
|
am = 1;
|
|
}
|
|
else if (self.impulse == 3)
|
|
{
|
|
fl = IT_SUPER_SHOTGUN;
|
|
new_idle = 5;
|
|
if (self.ammo_shells < 1)
|
|
am = 1;
|
|
}
|
|
else if (self.impulse == 4)
|
|
{
|
|
fl = IT_NAILGUN;
|
|
new_idle = 5;
|
|
if (self.ammo_nails < 1)
|
|
am = 1;
|
|
}
|
|
else if (self.impulse == 5)
|
|
{
|
|
fl = IT_SUPER_NAILGUN;
|
|
if (self.ammo_nails < 2)
|
|
am = 1;
|
|
}
|
|
else if (self.impulse == 6)
|
|
{
|
|
fl = IT_GRENADE_LAUNCHER;
|
|
new_idle = 5;
|
|
if (self.ammo_rockets < 1)
|
|
am = 1; // not available yet
|
|
}
|
|
else if (self.impulse == 7)
|
|
{
|
|
fl = IT_ROCKET_LAUNCHER;
|
|
new_idle = 5;
|
|
if (self.ammo_rockets < 1)
|
|
am = 1;
|
|
}
|
|
else if (self.impulse == 8)
|
|
{
|
|
fl = IT_LIGHTNING;
|
|
new_idle = 2;
|
|
if (self.ammo_cells < 1)
|
|
am = 1;
|
|
}
|
|
else if (self.impulse == 13) // mega-weapon
|
|
{
|
|
fl = IT_SPECIAL_WEAPON;
|
|
new_idle = 11;
|
|
if (self.ammo_special < 1)
|
|
am = 1;
|
|
}
|
|
|
|
self.impulse = 0;
|
|
|
|
if ((!(self.items & fl)) && (deathmatch || coop)) // X-Men: in singleplayer, weapons are already present
|
|
{ // don't have the weapon or the ammo
|
|
sprint (self, "no weapon.\n");
|
|
return;
|
|
}
|
|
|
|
if (am)
|
|
{ // don't have the ammo
|
|
sprint (self, "not enough ammo.\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// set weapon, set ammo
|
|
//
|
|
// self.weapon_idleframe = new_idle;
|
|
|
|
if (self.weapon != fl)
|
|
SetNewWeapon(fl);
|
|
else if (self.weapon == IT_AXE) {
|
|
self.weapon = fl;
|
|
SpecialWeaponChange();
|
|
W_SetCurrentAmmo ();
|
|
}
|
|
};
|
|
|
|
/*
|
|
============
|
|
CheatCommand
|
|
============
|
|
*/
|
|
void() CheatCommand = // cheats disabled
|
|
{
|
|
if (deathmatch)// || coop)
|
|
return;
|
|
|
|
self.ammo_rockets = 100;
|
|
self.ammo_nails = 200;
|
|
self.ammo_shells = 150;
|
|
self.items = self.items |
|
|
IT_AXE |
|
|
IT_SHOTGUN |
|
|
IT_SUPER_SHOTGUN |
|
|
IT_NAILGUN |
|
|
IT_SUPER_NAILGUN |
|
|
IT_GRENADE_LAUNCHER |
|
|
IT_ROCKET_LAUNCHER |
|
|
IT_KEY1 | IT_KEY2;
|
|
|
|
self.ammo_cells = 200;
|
|
self.items = self.items | IT_LIGHTNING;
|
|
|
|
// SetNewWeapon(IT_ROCKET_LAUNCHER);
|
|
|
|
|
|
// self.weapon = IT_ROCKET_LAUNCHER;
|
|
self.impulse = 0;
|
|
// W_SetCurrentAmmo ();
|
|
};
|
|
|
|
/*
|
|
============
|
|
CycleWeaponCommand
|
|
|
|
Go to the next weapon with ammo
|
|
============
|
|
*/
|
|
void() CycleWeaponCommand =
|
|
{
|
|
local float it, am, fl;
|
|
|
|
if (self.modelindex == index_skeleton)
|
|
return;
|
|
|
|
it = self.items;
|
|
self.impulse = 0;
|
|
fl = self.weapon;
|
|
|
|
if (deathmatch == DM_SPECIAL_POWERS) {
|
|
self.special_weapon = !self.special_weapon;
|
|
self.weapon = fl;
|
|
SpecialWeaponChange();
|
|
W_SetCurrentAmmo ();
|
|
|
|
return;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
am = 0;
|
|
|
|
if (fl == IT_LIGHTNING)
|
|
{
|
|
fl = IT_AXE;
|
|
}
|
|
else if (fl == IT_AXE)
|
|
{
|
|
fl = IT_SHOTGUN;
|
|
if (self.ammo_shells < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_SHOTGUN)
|
|
{
|
|
fl = IT_SUPER_SHOTGUN;
|
|
if (self.ammo_shells < 2)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_SUPER_SHOTGUN)
|
|
{
|
|
fl = IT_NAILGUN;
|
|
if (self.ammo_nails < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_NAILGUN)
|
|
{
|
|
fl = IT_SUPER_NAILGUN;
|
|
if (self.ammo_nails < 2)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_SUPER_NAILGUN)
|
|
{
|
|
fl = IT_GRENADE_LAUNCHER;
|
|
if (self.ammo_rockets < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_GRENADE_LAUNCHER)
|
|
{
|
|
fl = IT_ROCKET_LAUNCHER;
|
|
if (self.ammo_rockets < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_ROCKET_LAUNCHER)
|
|
{
|
|
fl = IT_LIGHTNING;
|
|
if (self.ammo_cells < 1)
|
|
am = 1;
|
|
}
|
|
|
|
if (am == 0)
|
|
{
|
|
SetNewWeapon(fl);
|
|
|
|
// W_SetCurrentAmmo ();
|
|
return;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
/*
|
|
============
|
|
CycleWeaponReverseCommand
|
|
|
|
Go to the prev weapon with ammo
|
|
============
|
|
*/
|
|
void() CycleWeaponReverseCommand =
|
|
{
|
|
local float it, am, fl;
|
|
|
|
if (self.modelindex == index_skeleton)
|
|
return;
|
|
|
|
it = self.items;
|
|
self.impulse = 0;
|
|
fl = self.weapon;
|
|
|
|
if (deathmatch == DM_SPECIAL_POWERS) {
|
|
self.special_weapon = !self.special_weapon;
|
|
self.weapon = fl;
|
|
SpecialWeaponChange();
|
|
W_SetCurrentAmmo ();
|
|
|
|
return;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
am = 0;
|
|
|
|
if (fl == IT_LIGHTNING)
|
|
{
|
|
fl = IT_ROCKET_LAUNCHER;
|
|
if (self.ammo_rockets < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_ROCKET_LAUNCHER)
|
|
{
|
|
fl = IT_GRENADE_LAUNCHER;
|
|
if (self.ammo_rockets < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_GRENADE_LAUNCHER)
|
|
{
|
|
fl = IT_SUPER_NAILGUN;
|
|
if (self.ammo_nails < 2)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_SUPER_NAILGUN)
|
|
{
|
|
fl = IT_NAILGUN;
|
|
if (self.ammo_nails < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_NAILGUN)
|
|
{
|
|
fl = IT_SUPER_SHOTGUN;
|
|
if (self.ammo_shells < 2)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_SUPER_SHOTGUN)
|
|
{
|
|
fl = IT_SHOTGUN;
|
|
if (self.ammo_shells < 1)
|
|
am = 1;
|
|
}
|
|
else if (fl == IT_SHOTGUN)
|
|
{
|
|
fl = IT_AXE;
|
|
}
|
|
else if (fl == IT_AXE)
|
|
{
|
|
fl = IT_LIGHTNING;
|
|
if (self.ammo_cells < 1)
|
|
am = 1;
|
|
}
|
|
|
|
if (am == 0)
|
|
{
|
|
SetNewWeapon(fl);
|
|
|
|
// W_SetCurrentAmmo ();
|
|
return;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
/*
|
|
============
|
|
ServerflagsCommand
|
|
|
|
Just for development
|
|
============
|
|
*/
|
|
void() ServerflagsCommand =
|
|
{
|
|
serverflags = serverflags * 2 + 1;
|
|
};
|
|
|
|
void() QuadCheat =
|
|
{
|
|
if (deathmatch || coop)
|
|
return;
|
|
self.super_time = 1;
|
|
self.super_damage_finished = time + 30;
|
|
self.items = self.items | IT_QUAD;
|
|
dprint ("quad cheat\n");
|
|
};
|
|
|
|
/*
|
|
============
|
|
Impulse Commands
|
|
|
|
============
|
|
*/
|
|
float capture, last_capture, capture_count, capture_index;
|
|
|
|
void() ImpulseCommands =
|
|
{
|
|
local float ftemp;
|
|
local string str;
|
|
|
|
if (self.impulse == 248) {
|
|
capture = !capture;
|
|
capture_index = 0;
|
|
}
|
|
|
|
if (!((self.change_weapon_status) || (self.weapon_flags & W_RELOADING) || ((self.think != player_run) && (self.think != player_stand1)))) {
|
|
// weapon is ready for changing
|
|
|
|
if (self.remember_impulse && (self.remember_impulse != 13)) { // prevent from changing while waiting for mega-weapon to come up
|
|
self.impulse = self.remember_impulse;
|
|
self.remember_impulse = 0;
|
|
}
|
|
|
|
if ((self.impulse >= 1 && self.impulse <= 8) || (self.impulse == 13))
|
|
W_ChangeWeapon ();
|
|
else if (self.impulse == 10)
|
|
CycleWeaponCommand ();
|
|
else if (self.impulse == 12)
|
|
CycleWeaponReverseCommand ();
|
|
}
|
|
else {
|
|
if ((self.impulse <= 13) && (!self.remember_impulse))
|
|
self.remember_impulse = self.impulse;
|
|
}
|
|
|
|
if (!self.impulse)
|
|
return;
|
|
|
|
else if (self.impulse == 11)
|
|
ServerflagsCommand ();
|
|
|
|
else if (self.impulse == 20) // re-print last trigger_multiple/single message
|
|
centerprint(self, self.last_centerprint);
|
|
|
|
else if (self.impulse == 40) // toggle chasecam
|
|
{
|
|
if (self.chasecam == world)
|
|
InitCam(self);
|
|
else
|
|
DisableCam(self);
|
|
}
|
|
|
|
// any impulses > 200 are debuggin only
|
|
if (deathmatch) {
|
|
self.impulse = 0;
|
|
return;
|
|
}
|
|
|
|
else if (self.impulse == 99)
|
|
CheatCommand ();
|
|
else if (self.impulse == 200)
|
|
show_damage = !show_damage;
|
|
|
|
else if (self.impulse == 202) { // give all weapon parts
|
|
self.weapon_parts = 4;
|
|
serverflags = serverflags | 15;
|
|
}
|
|
|
|
else if (self.impulse == 250) {
|
|
ftemp = cvar("coop") - 1;
|
|
if (ftemp < 1) ftemp = 12;
|
|
str = ftos(ftemp);
|
|
cvar_set("coop", str);
|
|
stuffcmd(self, "restart\n");
|
|
}
|
|
else if (self.impulse == 251) {
|
|
ftemp = cvar("coop") + 1;
|
|
if (ftemp > 12) ftemp = 1;
|
|
str = ftos(ftemp);
|
|
cvar_set("coop", str);
|
|
stuffcmd(self, "restart\n");
|
|
}
|
|
|
|
else if (self.impulse == 222) {
|
|
if (self.x_flags & X_GODCHEAT) {
|
|
self.x_flags = self.x_flags - X_GODCHEAT;
|
|
self.flags = self.flags - (self.flags & FL_GODMODE);
|
|
stuffcmd(self, "bf\n");
|
|
sprint(self, "Invincibility disabled\n");
|
|
}
|
|
else {
|
|
self.x_flags = self.x_flags | X_GODCHEAT;
|
|
self.flags = self.flags | FL_GODMODE;
|
|
sprint(self, "Invincibility enabled\n");
|
|
}
|
|
}
|
|
|
|
// else if (self.impulse == 255)
|
|
// QuadCheat ();
|
|
|
|
self.impulse = 0;
|
|
};
|
|
|
|
/*
|
|
============
|
|
W_WeaponFrame
|
|
|
|
Called every frame so impulse events can be handled as well as possible
|
|
============
|
|
*/
|
|
void() W_WeaponFrame =
|
|
{
|
|
if ((self.change_weapon_status) && (self.last_fade < (time - 0.07))) {
|
|
if (self.change_weapon_status == CW_FADEOUT)
|
|
FadeWeaponOut();
|
|
else
|
|
FadeWeaponIn();
|
|
}
|
|
|
|
ImpulseCommands ();
|
|
|
|
if (time < self.attack_finished)
|
|
return;
|
|
|
|
if (self.change_weapon_status)
|
|
return;
|
|
|
|
// check for attack
|
|
if ((self.button0) && (self.modelindex != index_skeleton))
|
|
{
|
|
SuperDamageSound ();
|
|
W_Attack ();
|
|
|
|
if ((self.flags & FL_FLAMEON) &&
|
|
(self.weapon != IT_SUPER_NAILGUN)) {
|
|
self.flags = self.flags - FL_FLAMEON;
|
|
}
|
|
}
|
|
else {
|
|
self.flags = self.flags - (self.flags & FL_FLAMEON);
|
|
}
|
|
|
|
};
|
|
|
|
/*
|
|
========
|
|
SuperDamageSound
|
|
|
|
Plays sound if needed
|
|
========
|
|
*/
|
|
void() SuperDamageSound =
|
|
{
|
|
if (self.super_damage_finished > time)
|
|
{
|
|
if (self.super_sound < time)
|
|
{
|
|
self.super_sound = time + 1;
|
|
sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
return;
|
|
};
|