t.message = self.message;
t.killtarget = self.killtarget;
t.target = self.target;
+ t.target2 = self.target2;
+ t.target3 = self.target3;
+ t.target4 = self.target4;
return;
}
stemp = self;
otemp = other;
+ if(stemp.target_random)
+ RandomSelection_Init();
+
for(i = 0; i < 4; ++i)
{
switch(i)
for(t = world; (t = find(t, targetname, s)); )
if(t.use)
{
- //print(stemp.classname, " ", stemp.targetname, " -> ", t.classname, " ", t.targetname, "\n");
- self = t;
- other = stemp;
- activator = act;
- self.use();
+ if(stemp.target_random)
+ {
+ RandomSelection_Add(t, 0, string_null, 1, 0);
+ }
+ else
+ {
+ self = t;
+ other = stemp;
+ activator = act;
+ self.use();
+ }
}
}
}
+ if(stemp.target_random && RandomSelection_chosen_ent)
+ {
+ self = RandomSelection_chosen_ent;
+ other = stemp;
+ activator = act;
+ self.use();
+ }
+
activator = act;
self = stemp;
other = otemp;
}
if (self.noise)
- sound (self.enemy, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
+ sound (self.enemy, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
// don't trigger again until reset
self.takedamage = DAMAGE_NO;
void multi_touch()
{
if not(self.spawnflags & 2)
- {
if not(other.iscreature)
return;
- if(self.team)
- if(self.team == other.team)
+ if(self.team)
+ if((self.spawnflags & 4 == 0) == (self.team != other.team))
return;
- }
// if the trigger has an angles field, check player's facing direction
if (self.movedir != '0 0 0')
self.reset = counter_reset;
};
+void trigger_hurt_use()
+{
+ if(activator.classname == "player")
+ self.enemy = activator;
+ else
+ self.enemy = world; // let's just destroy it, if taking over is too much work
+}
+
.float triggerhurttime;
void trigger_hurt_touch()
{
if (self.active != ACTIVE_ACTIVE)
return;
+ if(self.team)
+ if((self.spawnflags & 4 == 0) == (self.team != other.team))
+ return;
+
// only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
if (other.iscreature)
{
{
EXACTTRIGGER_TOUCH;
other.triggerhurttime = time + 1;
- Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
+
+ entity own;
+ own = self.enemy;
+ if(own.classname != "player")
+ {
+ own = self;
+ self.enemy = world; // I still hate you all
+ }
+
+ Damage (other, self, own, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
}
}
else
EXACTTRIGGER_INIT;
self.active = ACTIVE_ACTIVE;
self.touch = trigger_hurt_touch;
+ self.use = trigger_hurt_use;
+ self.enemy = world; // I hate you all
if (!self.dmg)
self.dmg = 1000;
if (!self.message)
if (other.health < self.max_health)
{
other.health = min(other.health + self.health, self.max_health);
- other.pauserothealth_finished = max(other.pauserothealth_finished, time + cvar("g_balance_pause_health_rot"));
- sound (other, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
+ other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+ sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
}
}
}
{
other.gravity = g;
if(self.noise != "")
- sound (other, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
+ sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
UpdateCSQCProjectile(self.owner);
}
};
// TODO add a way to do looped sounds with sound(); then complete this entity
.float volume, atten;
-void target_speaker_use() {sound(self, CHAN_TRIGGER, self.noise, VOL_BASE * self.volume, self.atten);}
+void target_speaker_use_off();
+void target_speaker_use_activator()
+{
+ if(clienttype(activator) != CLIENTTYPE_REAL)
+ return;
+ string snd;
+ if(substring(self.noise, 0, 1) == "*")
+ {
+ var .string sample;
+ sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
+ if(GetPlayerSoundSampleField_notFound)
+ snd = "misc/null.wav";
+ else if(activator.sample == "")
+ snd = "misc/null.wav";
+ else
+ {
+ tokenize_console(activator.sample);
+ float n;
+ n = stof(argv(1));
+ if(n > 0)
+ snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+ else
+ snd = strcat(argv(0), ".wav"); // randomization
+ }
+ }
+ else
+ snd = self.noise;
+ msg_entity = activator;
+ soundto(MSG_ONE, self, CH_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
+}
+void target_speaker_use_on()
+{
+ string snd;
+ if(substring(self.noise, 0, 1) == "*")
+ {
+ var .string sample;
+ sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
+ if(GetPlayerSoundSampleField_notFound)
+ snd = "misc/null.wav";
+ else if(activator.sample == "")
+ snd = "misc/null.wav";
+ else
+ {
+ tokenize_console(activator.sample);
+ float n;
+ n = stof(argv(1));
+ if(n > 0)
+ snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+ else
+ snd = strcat(argv(0), ".wav"); // randomization
+ }
+ }
+ else
+ snd = self.noise;
+ sound(self, CH_TRIGGER_SINGLE, snd, VOL_BASE * self.volume, self.atten);
+ if(self.spawnflags & 3)
+ self.use = target_speaker_use_off;
+}
+void target_speaker_use_off()
+{
+ sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASE * self.volume, self.atten);
+ self.use = target_speaker_use_on;
+}
+void target_speaker_reset()
+{
+ if(self.spawnflags & 1) // LOOPED_ON
+ {
+ if(self.use == target_speaker_use_on)
+ target_speaker_use_on();
+ }
+ else if(self.spawnflags & 2)
+ {
+ if(self.use == target_speaker_use_off)
+ target_speaker_use_off();
+ }
+}
void spawnfunc_target_speaker()
{
+ // TODO: "*" prefix to sound file name
+ // TODO: wait and random (just, HOW? random is not a field)
if(self.noise)
precache_sound (self.noise);
- IFTARGETED
+
+ if(!self.atten && !(self.spawnflags & 4))
{
- if(!self.atten)
+ IFTARGETED
self.atten = ATTN_NORM;
- else if(self.atten < 0)
- self.atten = 0;
- if(!self.volume)
- self.volume = 1;
- self.use = target_speaker_use;
+ else
+ self.atten = ATTN_STATIC;
+ }
+ else if(self.atten < 0)
+ self.atten = 0;
+
+ if(!self.volume)
+ self.volume = 1;
+
+ IFTARGETED
+ {
+ if(self.spawnflags & 8) // ACTIVATOR
+ self.use = target_speaker_use_activator;
+ else if(self.spawnflags & 1) // LOOPED_ON
+ {
+ target_speaker_use_on();
+ self.reset = target_speaker_reset;
+ }
+ else if(self.spawnflags & 2) // LOOPED_OFF
+ {
+ self.use = target_speaker_use_on;
+ self.reset = target_speaker_reset;
+ }
+ else
+ self.use = target_speaker_use_on;
+ }
+ else if(self.spawnflags & 1) // LOOPED_ON
+ {
+ ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
+ remove(self);
+ }
+ else if(self.spawnflags & 2) // LOOPED_OFF
+ {
+ objerror("This sound entity can never be activated");
}
else
{
- if(!self.atten)
- self.atten = ATTN_STATIC;
- else if(self.atten < 0)
- self.atten = 0;
- if(!self.volume)
- self.volume = 1;
+ // Quake/Nexuiz fallback
ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
+ remove(self);
}
};
{
vector o;
entity oldself;
+ entity hitent;
+ vector hitloc;
self.nextthink = time;
o = self.origin + v_forward * 32768;
}
- if(self.dmg)
+ if(self.dmg || self.enemy.target != "")
{
- if(self.dmg < 0)
- FireRailgunBullet(self.origin, o, 100000, 0, 0, 0, 0, 0, DEATH_HURTTRIGGER);
- else
- FireRailgunBullet(self.origin, o, self.dmg * frametime, 0, 0, 0, 0, 0, DEATH_HURTTRIGGER);
+ traceline(self.origin, o, MOVE_NORMAL, self);
}
+ hitent = trace_ent;
+ hitloc = trace_endpos;
if(self.enemy.target != "") // DETECTOR laser
{
- traceline(self.origin, o, MOVE_NORMAL, self);
if(trace_ent.iscreature)
{
- self.pusher = trace_ent;
+ self.pusher = hitent;
if(!self.count)
{
self.count = 1;
}
}
}
+
+ if(self.dmg)
+ {
+ if(self.team)
+ if((self.spawnflags & 8 == 0) == (self.team != hitent.team))
+ return;
+ if(hitent.takedamage)
+ Damage(hitent, self, self, ((self.dmg < 0) ? 100000 : (self.dmg * frametime)), DEATH_HURTTRIGGER, hitloc, '0 0 0');
+ }
}
float laser_SendEntity(entity to, float fl)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
- fl = fl - (fl & 0xE0); // use that bit to indicate finite length laser
+ fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
if(self.spawnflags & 2)
fl |= 0x80;
if(self.alpha)
fl |= 0x40;
if(self.scale != 1 || self.modelscale != 1)
fl |= 0x20;
+ if(self.spawnflags & 4)
+ fl |= 0x10;
WriteByte(MSG_ENTITY, fl);
if(fl & 1)
{
WriteByte(MSG_ENTITY, bound(0, self.scale * 16.0, 255));
WriteByte(MSG_ENTITY, bound(0, self.modelscale * 16.0, 255));
}
- WriteShort(MSG_ENTITY, self.cnt + 1);
+ if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
+ WriteShort(MSG_ENTITY, self.cnt + 1);
}
if(fl & 2)
{
self.scale = 1;
if(!self.modelscale)
self.modelscale = 1;
+ else if(self.modelscale < 0)
+ self.modelscale = 0;
self.think = misc_laser_think;
self.nextthink = time;
InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET);
if (self.active != ACTIVE_ACTIVE)
return;
- // FIXME: Better checking for what to push and not.
- if not(other.iscreature)
- if (other.classname != "corpse")
- if (other.classname != "body")
- if (other.classname != "gib")
- if (other.classname != "missile")
- if (other.classname != "rocket")
- if (other.classname != "casing")
- if (other.classname != "grenade")
- if (other.classname != "plasma")
- if (other.classname != "plasma_prim")
- if (other.classname != "plasma_chain")
- if (other.classname != "droppedweapon")
- if (other.classname != "nexball_basketball")
- if (other.classname != "nexball_football")
- return;
-
- if (other.deadflag && other.iscreature)
+ if (!isPushable(other))
return;
EXACTTRIGGER_TOUCH;
if(!pushdeltatime) return;
other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime;
- other.flags &~= FL_ONGROUND;
+ other.flags &~= FL_ONGROUND;
+ UpdateCSQCProjectile(other);
}
// Directionless (accelerator/decelerator) mode
if (self.active != ACTIVE_ACTIVE)
return;
- // FIXME: Better checking for what to push and not.
- if not(other.iscreature)
- if (other.classname != "corpse")
- if (other.classname != "body")
- if (other.classname != "gib")
- if (other.classname != "missile")
- if (other.classname != "rocket")
- if (other.classname != "casing")
- if (other.classname != "grenade")
- if (other.classname != "plasma")
- if (other.classname != "plasma_prim")
- if (other.classname != "plasma_chain")
- if (other.classname != "droppedweapon")
- if (other.classname != "nexball_basketball")
- if (other.classname != "nexball_football")
- return;
-
- if (other.deadflag && other.iscreature)
+ if (!isPushable(other))
return;
EXACTTRIGGER_TOUCH;
// div0: ticrate independent, 1 = identity (not 20)
other.velocity = other.velocity * pow(self.strength, pushdeltatime);
+ UpdateCSQCProjectile(other);
}
// Spherical (gravity/repulsor) mode
if (self.active != ACTIVE_ACTIVE)
return;
- // FIXME: Better checking for what to push and not.
- if not(other.iscreature)
- if (other.classname != "corpse")
- if (other.classname != "body")
- if (other.classname != "gib")
- if (other.classname != "missile")
- if (other.classname != "rocket")
- if (other.classname != "casing")
- if (other.classname != "grenade")
- if (other.classname != "plasma")
- if (other.classname != "plasma_prim")
- if (other.classname != "plasma_chain")
- if (other.classname != "droppedweapon")
- if (other.classname != "nexball_basketball")
- if (other.classname != "nexball_football")
- return;
-
- if (other.deadflag && other.iscreature)
+ if (!isPushable(other))
return;
EXACTTRIGGER_TOUCH;
str = self.strength;
other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
+ UpdateCSQCProjectile(other);
}
/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
EXACTTRIGGER_INIT;
if(self.radius)
{
- if(!self.strength) self.strength = 2000 * cvar("g_triggerimpulse_radial_multiplier");
+ if(!self.strength) self.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier;
setorigin(self, self.origin);
setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
self.touch = trigger_impulse_touch3;
{
if(self.target)
{
- if(!self.strength) self.strength = 950 * cvar("g_triggerimpulse_directional_multiplier");
+ if(!self.strength) self.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier;
self.touch = trigger_impulse_touch1;
}
else
{
if(!self.strength) self.strength = 0.9;
- self.strength = pow(self.strength, cvar("g_triggerimpulse_accel_power")) * cvar("g_triggerimpulse_accel_multiplier");
+ self.strength = pow(self.strength, autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
self.touch = trigger_impulse_touch2;
}
}
attach_sameorigin(dst, src, self.message);
}
+ dst.solid = SOLID_NOT; // solid doesn't work with attachment
remove(self);
}
else