game-source/klik/misc.qc
2011-03-20 17:27:47 +09:00

471 lines
8.1 KiB
C++

#include "common.qh"
#include "protocol.qh"
#include "misc.qh"
#include "server.qh"
#include "teleport.qh"
#include "weapon.qh"
.float tl_notsolid;
// ===================================================================== //
entity (string clname)
spawn =
{
local entity e;
e = BUILTIN_spawn ();
e.classname = clname;
return e;
};
// ===================================================================== //
void ()
SUB_remove =
{
remove (self);
};
void (entity e)
safe_remove =
{
e.takedamage = DAMAGE_NO;
e.solid = SOLID_NOT;
e.model = nil;
e.modelindex = 0;
e.think = SUB_remove;
e.nextthink = time;
};
// ===================================================================== //
void ()
SUB_makestatic =
{
makestatic (self);
};
void (entity e)
safe_makestatic =
{
if (sv_spawning) {
makestatic (self);
return;
}
e.takedamage = DAMAGE_NO;
e.solid = SOLID_NOT;
e.think = SUB_makestatic;
e.nextthink = time;
};
// ===================================================================== //
void ()
_sound_vector_think =
{
sound (self, CHAN_VOICE, self.noise1, self.volume, self.attenuation);
remove (self);
};
void (vector org, string samp, float vol, float atten)
sound_vector =
{
local entity e;
e = spawn("SOUND");
e.origin = org;
e.noise1 = samp;
e.volume = vol;
e.attenuation = atten;
e.think = _sound_vector_think;
e.nextthink = time;
};
// ===================================================================== //
float (vector org)
_missile_th_teleport =
{
self.owner = world;
return TRUE;
};
void (entity mis) missile_check_teleport;
void ()
_missile_always_trigger =
{
self.think = SUB_remove;
self.nextthink = self.attack_finished;
if ((self.movetype != MOVETYPE_FLYMISSILE)
&& (self.movetype != MOVETYPE_FLY))
return;
tl_proj_begin ();
/* Make sure we're still going to hit the thing */
traceline (self.origin, self.origin + self.velocity * sv_maxtic * 2, FALSE,
self);
if (trace_ent == self.enemy)
tl_touch (trace_ent, self);
else
self.enemy = world;
tl_proj_end ();
missile_check_teleport (self);
};
void (entity mis)
missile_check_teleport =
{
local float duration;
tl_proj_begin ();
trace_ent = mis;
trace_endpos = mis.origin;
duration = mis.attack_finished - time;
while (duration > sv_maxtic) {
traceline (trace_endpos, trace_endpos + mis.velocity * duration,
FALSE, trace_ent);
if (!trace_ent || trace_ent.solid == SOLID_BSP) {
/* Don't bother tracing through BSP, it won't happen. */
break;
}
if (tl_issolid (trace_ent) || mis.enemy == trace_ent
|| (duration * trace_fraction) <= sv_maxtic) {
/* We hit a triggered trigger,
a solid ent, or something we _just_ hit */
if (trace_fraction == 0) {
/* We're not going anywhere. Fudge it. */
break;
}
/* Trace on past it. */
duration -= duration * trace_fraction;
continue;
}
/* Reached a [new] trigger */
mis.enemy = trace_ent;
mis.think = _missile_always_trigger;
mis.nextthink = time + duration * trace_fraction - sv_maxtic;
break;
}
tl_proj_end ();
};
entity (string clname, string mod, vector org, vector dir, float spd)
spawn_missile =
{
newmis = spawn (clname);
newmis.owner = self;
newmis.goalentity = self;
newmis.movetype = MOVETYPE_FLYMISSILE;
newmis.solid = SOLID_BBOX;
newmis.deadflag = DEAD_NONLIVING;
newmis.th_teleport = _missile_th_teleport;
setmodel (newmis, mod);
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, org);
newmis.angles = vectoangles (dir);
newmis.speed = spd;
newmis.velocity = dir * spd;
newmis.attack_finished = time + (6000 / spd);
newmis.think = SUB_remove;
newmis.nextthink = newmis.attack_finished;
missile_check_teleport (newmis);
return newmis;
};
// ===================================================================== //
entity tl_first;
.entity tl_next;
void ()
tl_proj_begin =
{
local entity walk;
tl_first = world;
for (walk = nextent (world); walk; walk = nextent (walk)) {
if (walk.solid != SOLID_TRIGGER)
continue;
walk.tl_next = tl_first;
tl_first = walk;
walk.solid = SOLID_BBOX;
walk.tl_notsolid = TRUE;
setorigin (walk, walk.origin); // relink
}
};
void ()
tl_proj_end =
{
local entity walk;
for (walk = tl_first; walk; walk = walk.tl_next) {
walk.solid = SOLID_TRIGGER;
walk.tl_notsolid = FALSE;
setorigin (walk, walk.origin); // relink
}
};
void (entity trigger, entity fake_proj)
tl_touch =
{
local entity oldself, oldother;
if (!trigger.touch)
return;
tl_proj_end ();
oldself = self;
oldother = other;
self = trigger;
other = fake_proj;
self.touch ();
self = oldself;
other = oldother;
tl_proj_begin ();
};
// ===================================================================== //
string (entity e)
name =
{
if (e.netname)
return e.netname;
if (e.classname)
return e.classname;
if (e.velocity)
return "an unidentified flying object";
return "an unidentified stationary object";
};
// ===================================================================== //
void (.string fld, string match, void (entity e) func)
foreach =
{
local entity ent;
ent = world;
while ((ent = find (ent, fld, match))) {
if (!func) {
dprint ("NULL function in foreach, classname: ", ent.classname,
"\n");
continue;
}
func (ent);
}
};
void (.string fld, string match, .void () func)
foreach_field =
{
local entity oldself;
oldself = self;
self = world;
while ((self = find (self, fld, match))) {
if (!self.func) {
dprint ("NULL function in foreach_field, classname: ",
self.classname, "\n");
continue;
}
self.func ();
}
self = oldself;
};
// ===================================================================== //
float (entity newself, entity newother, float () func)
switcheroo = {
local entity oldself, oldother;
local float ret;
oldself = self;
oldother = other;
self = newself;
other = newother;
ret = func ();
self = oldself;
other = oldother;
return ret;
};
// ===================================================================== //
float (float current, float increment, float max)
increase_bound =
{
local float diff;
diff = max - current;
if (diff <= 0)
return current;
if (diff > increment)
diff = increment;
return current + diff;
};
float (.float fld, float increment, float max)
increase_field =
{
local float new;
new = increase_bound (self.fld, increment, max);
if (new == self.fld)
return FALSE;
self.fld = new;
return TRUE;
};
// ===================================================================== //
/* Not to be confused with maxspeed */
float (entity e)
calc_max_speed =
{
local float spd;
spd = e.maxspeed;
if (self.waterlevel >= 2)
spd = spd * 0.7; // Bah. Hard coded in engine.
else if (!self.waterlevel && !(self.flags & FL_ONGROUND)) {
if (spd > 30)
spd = 30; // Also hard coded.
}
return spd;
};
// ===================================================================== //
entity _xprint_client;
float _xprint_level;
void (entity client, float level)
xprint_start =
{
_xprint_client = client;
_xprint_level = level;
};
void (string str)
xprint_str =
{
msg_entity = _xprint_client;
WriteBytes (MSG_ONE, SVC_PRINT, _xprint_level);
WriteString (MSG_ONE, str);
};
// ===================================================================== //
entity (.string fld, string str)
find_random =
{
local float r, numents;
local entity ent;
numents = 0;
r = floor (random () * 512);
while (1) {
ent = find (world, fld, str);
if (!ent)
return world;
while (ent) {
numents++;
r--;
if (r <= 0)
return ent;
ent = find (ent, fld, str);
}
r -= numents * floor (r / numents);
}
return world;
};
// ===================================================================== //
entity (entity ech)
random_enemy_chain =
{
local entity walk;
local float tot, r;
r = floor (random () * 64) + 1;
tot = 1;
for (walk = ech.enemy; walk != ech; walk = walk.enemy) {
r--;
if (r <= 0)
return walk;
tot++;
}
if (!tot)
return ech;
/* Ok, only look at half the remaining ones */
tot = floor (tot * 0.5);
if (!tot)
return ech.enemy;
r -= tot * floor(r / tot);
for (walk = ech.enemy; walk; walk = walk.enemy) {
if (r <= 0)
return walk;
r--;
}
return world;
};