// const int CH_BGM_SINGLE = -8;
const int CH_BGM_SINGLE = 8;
const int CH_AMBIENT = -9;
-// const int CH_AMBIENT_SINGLE = 9;
+const int CH_AMBIENT_SINGLE = 9;
const float ATTEN_NONE = 0;
const float ATTEN_MIN = 0.015625;
} \
} MACRO_END
+ string _Sound_fixpath(string base)
+ {
+ if (base == "") return string_null;
+ #ifdef SVQC
+ return strcat(base, ".wav"); // let the client engine decide
+ #else
+ #define extensions(x) \
+ x(wav) \
+ x(ogg) \
+ x(flac) \
+ /**/
+ #define tryext(ext) { \
+ string s = strcat(base, "." #ext); \
+ if (fexists(strcat("sound/", s))) { \
+ return s; \
+ } \
+ }
+ extensions(tryext);
+ LOG_WARNF("Missing sound: \"%s\"", strcat("sound/", base));
+ #undef tryext
+ #undef extensions
+ return string_null;
+ #endif
+ }
+
CLASS(Sound, Object)
ATTRIB(Sound, m_id, int, 0);
ATTRIB(Sound, sound_str, string());
+ ATTRIB(Sound, sound_str_, string);
CONSTRUCTOR(Sound, string() path)
{
CONSTRUCT(Sound);
this.sound_str = path;
}
- #define Sound_fixpath(this) _Sound_fixpath((this).sound_str())
- string _Sound_fixpath(string base)
- {
- if (base == "") return string_null;
- #ifdef SVQC
- return strcat(base, ".wav"); // let the client engine decide
- #else
- #define extensions(x) \
- x(wav) \
- x(ogg) \
- x(flac) \
- /**/
- #define tryext(ext) { string s = strcat(base, "." #ext); if (fexists(strcat("sound/", s))) return s; }
- extensions(tryext);
- LOG_WARNF("Missing sound: \"%s\"", strcat("sound/", base));
- #undef tryext
- #undef extensions
- return string_null;
- #endif
- }
METHOD(Sound, sound_precache, void(Sound this))
{
TC(Sound, this);
- string s = Sound_fixpath(this);
+ string s = _Sound_fixpath(this.sound_str());
if (!s) return;
profile(sprintf("precache_sound(\"%s\")", s));
precache_sound(s);
+ strcpy(this.sound_str_, s);
}
ENDCLASS(Sound)
+
+ entity _Sound_fixpath_this;
+ string _Sound_fixpath_cached;
+ #define Sound_fixpath(this) ( \
+ _Sound_fixpath_this = (this), \
+ _Sound_fixpath_cached = _Sound_fixpath_this.sound_str_, \
+ _Sound_fixpath_cached ? _Sound_fixpath_cached : _Sound_fixpath(_Sound_fixpath_this.sound_str()) \
+ )
#include "door.qh"
+#include "door_rotating.qh"
/*
Doors are similar to buttons, but can spawn a fat trigger field around them
void door_go_down(entity this);
void door_go_up(entity this, entity actor, entity trigger);
-void door_rotating_go_down(entity this);
-void door_rotating_go_up(entity this, entity oth);
void door_blocked(entity this, entity blocker)
{
- if((this.spawnflags & 8)
+ if((this.spawnflags & DOOR_CRUSH)
#ifdef SVQC
&& (blocker.takedamage != DAMAGE_NO)
#elif defined(CSQC)
if (this.wait >= 0)
{
if (this.state == STATE_DOWN)
- if (this.classname == "door")
- {
- door_go_up (this, NULL, NULL);
- } else
- {
- door_rotating_go_up(this, blocker);
- }
+ {
+ if (this.classname == "door")
+ door_go_up(this, NULL, NULL);
+ else
+ door_rotating_go_up(this, blocker);
+ }
else
- if (this.classname == "door")
- {
- door_go_down (this);
- } else
- {
- door_rotating_go_down (this);
- }
+ {
+ if (this.classname == "door")
+ door_go_down(this);
+ else
+ door_rotating_go_down(this);
+ }
}
}
#ifdef SVQC
if(!door.itemkeys)
{
#ifdef SVQC
- play2(player, SND(TALK));
+ play2(player, door.noise);
Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_UNLOCKED);
#endif
return true;
door_go_up(e, actor, trigger);
} else {
// if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
- if ((e.spawnflags & 2) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
+ if ((e.spawnflags & DOOR_ROTATING_BIDIR) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
e.lip = 666; // e.lip is used to remember reverse opening direction for door_rotating
e.pos2 = '0 0 0' - e.pos2;
}
// if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
- if (!((e.spawnflags & 2) && (e.spawnflags & 8) && e.state == STATE_DOWN
+ if (!((e.spawnflags & DOOR_ROTATING_BIDIR) && (e.spawnflags & DOOR_ROTATING_BIDIR_IN_DOWN) && e.state == STATE_DOWN
&& (((e.lip == 666) && (trigger.trigger_reverse == 0)) || ((e.lip != 666) && (trigger.trigger_reverse != 0)))))
{
door_rotating_go_up(e, trigger);
void door_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
{
- if(this.spawnflags & DOOR_NOSPLASH)
+ if(this.spawnflags & NOSPLASH)
if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
return;
this.health = this.health - damage;
void door_generic_plat_blocked(entity this, entity blocker)
{
- if((this.spawnflags & 8) && (blocker.takedamage != DAMAGE_NO)) { // Kill Kill Kill!!
+ if((this.spawnflags & DOOR_CRUSH) && (blocker.takedamage != DAMAGE_NO)) { // Kill Kill Kill!!
#ifdef SVQC
Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
#endif
}
}
-void door_rotating_hit_top(entity this)
-{
- if (this.noise1 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- this.state = STATE_TOP;
- if (this.spawnflags & DOOR_TOGGLE)
- return; // don't come down automatically
- setthink(this, door_rotating_go_down);
- this.nextthink = this.ltime + this.wait;
-}
-
-void door_rotating_hit_bottom(entity this)
-{
- if (this.noise1 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- if (this.lip==666) // this.lip is used to remember reverse opening direction for door_rotating
- {
- this.pos2 = '0 0 0' - this.pos2;
- this.lip = 0;
- }
- this.state = STATE_BOTTOM;
-}
-
-void door_rotating_go_down(entity this)
-{
- if (this.noise2 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- if (this.max_health)
- {
- this.takedamage = DAMAGE_YES;
- this.health = this.max_health;
- }
-
- this.state = STATE_DOWN;
- SUB_CalcAngleMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_rotating_hit_bottom);
-}
-
-void door_rotating_go_up(entity this, entity oth)
-{
- if (this.state == STATE_UP)
- return; // already going up
-
- if (this.state == STATE_TOP)
- { // reset top wait time
- this.nextthink = this.ltime + this.wait;
- return;
- }
- if (this.noise2 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- this.state = STATE_UP;
- SUB_CalcAngleMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_rotating_hit_top);
-
- string oldmessage;
- oldmessage = this.message;
- this.message = "";
- SUB_UseTargets(this, NULL, oth); // TODO: is oth needed here?
- this.message = oldmessage;
-}
-
-
/*
=========================================
door trigger
entity LinkDoors_nextent(entity cur, entity near, entity pass)
{
- while((cur = find(cur, classname, pass.classname)) && ((cur.spawnflags & 4) || cur.enemy))
+ while((cur = find(cur, classname, pass.classname)) && ((cur.spawnflags & DOOR_DONT_LINK) || cur.enemy))
{
}
return cur;
if (this.enemy)
return; // already linked by another door
- if (this.spawnflags & 4)
+ if (this.spawnflags & DOOR_DONT_LINK)
{
this.owner = this.enemy = this;
#ifdef SVQC
-// spawnflags require key (for now only func_door)
-spawnfunc(func_door)
+// common code for func_door and func_door_rotating spawnfuncs
+void door_init_shared(entity this)
{
- // Quake 1 keys compatibility
- if (this.spawnflags & SPAWNFLAGS_GOLD_KEY)
- this.itemkeys |= ITEM_KEY_BIT(0);
- if (this.spawnflags & SPAWNFLAGS_SILVER_KEY)
- this.itemkeys |= ITEM_KEY_BIT(1);
-
- SetMovedir(this);
-
this.max_health = this.health;
- if (!InitMovingBrushTrigger(this))
- return;
- this.effects |= EF_LOWPRECISION;
- this.classname = "door";
+ // unlock sound
if(this.noise == "")
+ {
this.noise = "misc/talk.wav";
+ }
+ // door still locked sound
if(this.noise3 == "")
+ {
this.noise3 = "misc/talk.wav";
+ }
precache_sound(this.noise);
precache_sound(this.noise3);
- setblocked(this, door_blocked);
- this.use = door_use;
-
- if(this.dmg && (this.message == ""))
+ if((this.dmg || (this.spawnflags & DOOR_CRUSH)) && (this.message == ""))
+ {
this.message = "was squished";
- if(this.dmg && (this.message2 == ""))
+ }
+ if((this.dmg || (this.spawnflags & DOOR_CRUSH)) && (this.message2 == ""))
+ {
this.message2 = "was squished by";
+ }
+ // TODO: other soundpacks
if (this.sounds > 0)
{
this.noise2 = "plats/medplat1.wav";
this.noise1 = "plats/medplat2.wav";
}
- if(this.noise1 && this.noise1 != "") { precache_sound(this.noise1); }
- if(this.noise2 && this.noise2 != "") { precache_sound(this.noise2); }
+ // sound when door stops moving
+ if(this.noise1 && this.noise1 != "")
+ {
+ precache_sound(this.noise1);
+ }
+ // sound when door is moving
+ if(this.noise2 && this.noise2 != "")
+ {
+ precache_sound(this.noise2);
+ }
- if (!this.speed)
- this.speed = 100;
if (!this.wait)
+ {
this.wait = 3;
+ }
if (!this.lip)
+ {
this.lip = 8;
+ }
+
+ this.state = STATE_BOTTOM;
+
+ if (this.health)
+ {
+ //this.canteamdamage = true; // TODO
+ this.takedamage = DAMAGE_YES;
+ this.event_damage = door_damage;
+ }
+
+ if (this.items)
+ {
+ this.wait = -1;
+ }
+}
+
+// spawnflags require key (for now only func_door)
+spawnfunc(func_door)
+{
+ // Quake 1 keys compatibility
+ if (this.spawnflags & SPAWNFLAGS_GOLD_KEY)
+ this.itemkeys |= ITEM_KEY_BIT(0);
+ if (this.spawnflags & SPAWNFLAGS_SILVER_KEY)
+ this.itemkeys |= ITEM_KEY_BIT(1);
+
+ SetMovedir(this);
+
+ if (!InitMovingBrushTrigger(this))
+ return;
+ this.effects |= EF_LOWPRECISION;
+ this.classname = "door";
+
+ setblocked(this, door_blocked);
+ this.use = door_use;
this.pos1 = this.origin;
this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
if (this.spawnflags & DOOR_START_OPEN)
InitializeEntity(this, door_init_startopen, INITPRIO_SETLOCATION);
- this.state = STATE_BOTTOM;
+ door_init_shared(this);
- if (this.health)
+ if (!this.speed)
{
- //this.canteamdamage = true; // TODO
- this.takedamage = DAMAGE_YES;
- this.event_damage = door_damage;
+ this.speed = 100;
}
- if (this.items)
- this.wait = -1;
-
settouch(this, door_touch);
// LinkDoors can't be done until all of the doors have been spawned, so
#ifdef SVQC
// NOTE: also contains func_sparks
-bool pointparticles_SendEntity(entity this, entity to, float fl)
+bool pointparticles_SendEntity(entity this, entity to, float sendflags)
{
WriteHeader(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
// optional features to save space
- fl = fl & 0x0F;
- if(this.spawnflags & 2)
- fl |= 0x10; // absolute count on toggle-on
+ sendflags = sendflags & 0x0F;
+ if(this.spawnflags & PARTICLES_IMPULSE)
+ sendflags |= SF_POINTPARTICLES_IMPULSE; // absolute count on toggle-on
if(this.movedir != '0 0 0' || this.velocity != '0 0 0')
- fl |= 0x20; // 4 bytes - saves CPU
+ sendflags |= SF_POINTPARTICLES_MOVING; // 4 bytes - saves CPU
if(this.waterlevel || this.count != 1)
- fl |= 0x40; // 4 bytes - obscure features almost never used
+ sendflags |= SF_POINTPARTICLES_JITTER_AND_COUNT; // 4 bytes - obscure features almost never used
if(this.mins != '0 0 0' || this.maxs != '0 0 0')
- fl |= 0x80; // 14 bytes - saves lots of space
+ sendflags |= SF_POINTPARTICLES_BOUNDS; // 14 bytes - saves lots of space
- WriteByte(MSG_ENTITY, fl);
- if(fl & 2)
+ WriteByte(MSG_ENTITY, sendflags);
+ if(sendflags & SF_TRIGGER_UPDATE)
{
- if(this.state)
+ if(this.active == ACTIVE_ACTIVE)
WriteCoord(MSG_ENTITY, this.impulse);
else
WriteCoord(MSG_ENTITY, 0); // off
}
- if(fl & 4)
+ if(sendflags & SF_TRIGGER_RESET)
{
WriteVector(MSG_ENTITY, this.origin);
}
- if(fl & 1)
+ if(sendflags & SF_TRIGGER_INIT)
{
if(this.model != "null")
{
WriteShort(MSG_ENTITY, this.modelindex);
- if(fl & 0x80)
+ if(sendflags & SF_POINTPARTICLES_BOUNDS)
{
WriteVector(MSG_ENTITY, this.mins);
WriteVector(MSG_ENTITY, this.maxs);
else
{
WriteShort(MSG_ENTITY, 0);
- if(fl & 0x80)
+ if(sendflags & SF_POINTPARTICLES_BOUNDS)
{
WriteVector(MSG_ENTITY, this.maxs);
}
}
WriteShort(MSG_ENTITY, this.cnt);
WriteString(MSG_ENTITY, this.mdl);
- if(fl & 0x20)
+ if(sendflags & SF_POINTPARTICLES_MOVING)
{
WriteShort(MSG_ENTITY, compressShortVector(this.velocity));
WriteShort(MSG_ENTITY, compressShortVector(this.movedir));
}
- if(fl & 0x40)
+ if(sendflags & SF_POINTPARTICLES_JITTER_AND_COUNT)
{
WriteShort(MSG_ENTITY, this.waterlevel * 16.0);
WriteByte(MSG_ENTITY, this.count * 16.0);
return 1;
}
-void pointparticles_use(entity this, entity actor, entity trigger)
-{
- this.state = !this.state;
- this.SendFlags |= 2;
-}
-
void pointparticles_think(entity this)
{
if(this.origin != this.oldorigin)
{
- this.SendFlags |= 4;
+ this.SendFlags |= SF_TRIGGER_RESET;
this.oldorigin = this.origin;
}
this.nextthink = time;
}
-void pointparticles_reset(entity this)
-{
- if(this.spawnflags & 1)
- this.state = 1;
- else
- this.state = 0;
-}
-
spawnfunc(func_pointparticles)
{
if(this.model != "") { precache_model(this.model); _setmodel(this, this.model); }
setsize(this, '0 0 0', this.maxs - this.mins);
}
//if(!this.cnt) this.cnt = _particleeffectnum(this.mdl);
+ this.setactive = generic_netlinked_setactive;
- Net_LinkEntity(this, (this.spawnflags & 4), 0, pointparticles_SendEntity);
+ Net_LinkEntity(this, (this.spawnflags & PARTICLES_VISCULLING), 0, pointparticles_SendEntity);
IFTARGETED
{
- this.use = pointparticles_use;
- this.reset = pointparticles_reset;
- this.reset(this);
+ // backwards compatibility
+ this.use = generic_netlinked_legacy_use;
}
- else
- this.state = 1;
+ this.reset = generic_netlinked_reset;
+ this.reset(this);
setthink(this, pointparticles_think);
this.nextthink = time;
}
spawnfunc(func_sparks)
{
- // this.cnt is the amount of sparks that one burst will spawn
- if(this.cnt < 1) {
- this.cnt = 25.0; // nice default value
+ if(this.count < 1) {
+ this.count = 25.0; // nice default value
}
- // this.wait is the probability that a sparkthink will spawn a spark shower
- // range: 0 - 1, but 0 makes little sense, so...
- if(this.wait < 0.05) {
- this.wait = 0.25; // nice default value
+ if(this.impulse < 0.5) {
+ this.impulse = 2.5; // nice default value
}
- this.count = this.cnt;
this.mins = '0 0 0';
this.maxs = '0 0 0';
this.velocity = '0 0 -1';
this.mdl = "TE_SPARK";
- this.impulse = 10 * this.wait; // by default 2.5/sec
- this.wait = 0;
this.cnt = 0; // use mdl
spawnfunc_func_pointparticles(this);
.int dphitcontentsmask;
entityclass(PointParticles);
- class(PointParticles) .int cnt; // effect number
- class(PointParticles) .vector velocity; // particle velocity
- class(PointParticles) .float waterlevel; // direction jitter
- class(PointParticles) .int count; // count multiplier
- class(PointParticles) .int impulse; // density
- class(PointParticles) .string noise; // sound
- class(PointParticles) .float atten;
- class(PointParticles) .float volume;
- class(PointParticles) .int absolute; // 1 = count per second is absolute, ABSOLUTE_ONLY_SPAWN_AT_TOGGLE = only spawn at toggle
- class(PointParticles) .vector movedir; // trace direction
- class(PointParticles) .float glow_color; // palette index
+ classfield(PointParticles) .int cnt; // effect number
+ classfield(PointParticles) .vector velocity; // particle velocity
+ classfield(PointParticles) .float waterlevel; // direction jitter
+ classfield(PointParticles) .int count; // count multiplier
+ classfield(PointParticles) .int impulse; // density
+ classfield(PointParticles) .string noise; // sound
+ classfield(PointParticles) .float atten;
+ classfield(PointParticles) .float volume;
-classfield(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
++classfield(PointParticles) .float absolute; // 1 = count per second is absolute, ABSOLUTE_ONLY_SPAWN_AT_TOGGLE = only spawn at toggle
+ classfield(PointParticles) .vector movedir; // trace direction
+ classfield(PointParticles) .float glow_color; // palette index
+const int ABSOLUTE_ONLY_SPAWN_AT_TOGGLE = 2;
+
void Draw_PointParticles(entity this)
{
float n, i, fail;
o = this.origin;
sz = this.maxs - this.mins;
n = doBGMScript(this);
- if(this.absolute == 2)
+ if(this.absolute == ABSOLUTE_ONLY_SPAWN_AT_TOGGLE)
{
if(n >= 0)
n = this.just_toggled ? this.impulse : 0;
void Ent_PointParticles_Remove(entity this)
{
- if(this.noise)
- strunzone(this.noise);
- this.noise = string_null;
- if(this.bgmscript)
- strunzone(this.bgmscript);
- this.bgmscript = string_null;
- if(this.mdl)
- strunzone(this.mdl);
- this.mdl = string_null;
+ strfree(this.noise);
+ strfree(this.bgmscript);
+ strfree(this.mdl);
}
NET_HANDLE(ENT_CLIENT_POINTPARTICLES, bool isnew)
{
float i;
vector v;
- int f = ReadByte();
- if(f & 2)
+ int sendflags = ReadByte();
+ if(sendflags & SF_TRIGGER_UPDATE)
{
i = ReadCoord(); // density (<0: point, >0: volume)
if(i && !this.impulse && (this.cnt || this.mdl)) // this.cnt check is so it only happens if the ent already existed
this.just_toggled = 1;
this.impulse = i;
}
- if(f & 4)
+ if(sendflags & SF_TRIGGER_RESET)
{
this.origin = ReadVector();
}
- if(f & 1)
+ if(sendflags & SF_TRIGGER_INIT)
{
this.modelindex = ReadShort();
- if(f & 0x80)
+ if(sendflags & SF_POINTPARTICLES_BOUNDS)
{
if(this.modelindex)
{
this.cnt = ReadShort(); // effect number
this.mdl = strzone(ReadString()); // effect string
- if(f & 0x20)
+ if(sendflags & SF_POINTPARTICLES_MOVING)
{
this.velocity = decompressShortVector(ReadShort());
this.movedir = decompressShortVector(ReadShort());
{
this.velocity = this.movedir = '0 0 0';
}
- if(f & 0x40)
+ if(sendflags & SF_POINTPARTICLES_JITTER_AND_COUNT)
{
this.waterlevel = ReadShort() / 16.0;
this.count = ReadByte() / 16.0;
this.waterlevel = 0;
this.count = 1;
}
- if(this.noise)
- strunzone(this.noise);
- if(this.bgmscript)
- strunzone(this.bgmscript);
- this.noise = strzone(ReadString());
+ strcpy(this.noise, ReadString());
if(this.noise != "")
{
this.atten = ReadByte() / 64.0;
this.volume = ReadByte() / 255.0;
}
- this.bgmscript = strzone(ReadString());
+ strcpy(this.bgmscript, ReadString());
if(this.bgmscript != "")
{
this.bgmscriptattack = ReadByte() / 64.0;
return = true;
- if(f & 2)
+ if(sendflags & SF_TRIGGER_UPDATE)
{
this.absolute = (this.impulse >= 0);
if(!this.absolute)
{
v = this.maxs - this.mins;
- this.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
+ this.impulse *= -v.x * v.y * v.z / (64**3); // relative: particles per 64^3 cube
}
}
- if(f & 0x10)
- this.absolute = 2;
+ if(sendflags & SF_POINTPARTICLES_IMPULSE)
+ this.absolute = ABSOLUTE_ONLY_SPAWN_AT_TOGGLE;
setorigin(this, this.origin);
setsize(this, this.mins, this.maxs);
vector a;
if(this.enemy)
{
- if(this.spawnflags & 2)
+ if(this.spawnflags & LASER_FINITE)
{
if(this.enemy.origin != this.mangle)
{
this.mangle = this.enemy.origin;
- this.SendFlags |= 2;
+ this.SendFlags |= SF_LASER_UPDATE_TARGET;
}
}
else
if(a != this.mangle)
{
this.mangle = a;
- this.SendFlags |= 2;
+ this.SendFlags |= SF_LASER_UPDATE_TARGET;
}
}
}
if(this.angles != this.mangle)
{
this.mangle = this.angles;
- this.SendFlags |= 2;
+ this.SendFlags |= SF_LASER_UPDATE_TARGET;
}
}
if(this.origin != this.oldorigin)
{
- this.SendFlags |= 1;
+ this.SendFlags |= SF_LASER_UPDATE_ORIGIN;
this.oldorigin = this.origin;
}
}
this.nextthink = time;
- if(!this.state)
+ if(this.active == ACTIVE_NOT)
return;
misc_laser_aim(this);
if(this.enemy)
{
o = this.enemy.origin;
- if (!(this.spawnflags & 2))
- o = this.origin + normalize(o - this.origin) * 32768;
+ if (!(this.spawnflags & LASER_FINITE))
+ o = this.origin + normalize(o - this.origin) * LASER_BEAM_MAXLENGTH;
}
else
{
makevectors(this.mangle);
- o = this.origin + v_forward * 32768;
+ o = this.origin + v_forward * LASER_BEAM_MAXLENGTH;
}
if(this.dmg || this.enemy.target != "")
if(this.dmg)
{
if(this.team)
- if(((this.spawnflags & 8) == 0) == (this.team != hitent.team))
+ if(((this.spawnflags & LASER_INVERT_TEAM) == 0) == (this.team != hitent.team))
return;
if(hitent.takedamage)
Damage(hitent, this, this, ((this.dmg < 0) ? 100000 : (this.dmg * frametime)), DEATH_HURTTRIGGER.m_id, DMG_NOWEP, hitloc, '0 0 0');
}
}
-bool laser_SendEntity(entity this, entity to, float fl)
+bool laser_SendEntity(entity this, entity to, float sendflags)
{
WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
- fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
- if(this.spawnflags & 2)
- fl |= 0x80;
+ sendflags = sendflags & 0x0F; // use that bit to indicate finite length laser
+ if(this.spawnflags & LASER_FINITE)
+ sendflags |= SF_LASER_FINITE;
if(this.alpha)
- fl |= 0x40;
+ sendflags |= SF_LASER_ALPHA;
if(this.scale != 1 || this.modelscale != 1)
- fl |= 0x20;
- if(this.spawnflags & 4)
- fl |= 0x10;
- WriteByte(MSG_ENTITY, fl);
- if(fl & 1)
+ sendflags |= SF_LASER_SCALE;
+ if(this.spawnflags & LASER_NOTRACE)
+ sendflags |= SF_LASER_NOTRACE;
+ WriteByte(MSG_ENTITY, sendflags);
+ if(sendflags & SF_LASER_UPDATE_ORIGIN)
{
WriteVector(MSG_ENTITY, this.origin);
}
- if(fl & 8)
+ if(sendflags & SF_LASER_UPDATE_EFFECT)
{
- WriteByte(MSG_ENTITY, this.colormod_x * 255.0);
- WriteByte(MSG_ENTITY, this.colormod_y * 255.0);
- WriteByte(MSG_ENTITY, this.colormod_z * 255.0);
- if(fl & 0x40)
+ WriteByte(MSG_ENTITY, this.beam_color.x * 255.0);
+ WriteByte(MSG_ENTITY, this.beam_color.y * 255.0);
+ WriteByte(MSG_ENTITY, this.beam_color.z * 255.0);
+ if(sendflags & SF_LASER_ALPHA)
WriteByte(MSG_ENTITY, this.alpha * 255.0);
- if(fl & 0x20)
+ if(sendflags & SF_LASER_SCALE)
{
WriteByte(MSG_ENTITY, bound(0, this.scale * 16.0, 255));
WriteByte(MSG_ENTITY, bound(0, this.modelscale * 16.0, 255));
}
- if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
- WriteShort(MSG_ENTITY, this.cnt + 1);
+ if((sendflags & SF_LASER_FINITE) || !(sendflags & SF_LASER_NOTRACE)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
+ WriteShort(MSG_ENTITY, this.cnt);
}
- if(fl & 2)
+ if(sendflags & SF_LASER_UPDATE_TARGET)
{
- if(fl & 0x80)
+ if(sendflags & SF_LASER_FINITE)
{
WriteVector(MSG_ENTITY, this.enemy.origin);
}
WriteAngle(MSG_ENTITY, this.mangle_y);
}
}
- if(fl & 4)
- WriteByte(MSG_ENTITY, this.state);
- return 1;
+ if(sendflags & SF_LASER_UPDATE_ACTIVE)
+ WriteByte(MSG_ENTITY, this.active);
+ return true;
}
/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
spawnfunc_target_position where the laser ends
"mdl"
name of beam end effect to use
-"colormod"
+"beam_color"
color of the beam (default: red)
"dmg"
damage per second (-1 for a laser that kills immediately)
*/
-void laser_use(entity this, entity actor, entity trigger)
+
+void laser_setactive(entity this, int act)
{
- this.state = !this.state;
- this.SendFlags |= 4;
- misc_laser_aim(this);
+ int old_status = this.active;
+ if(act == ACTIVE_TOGGLE)
+ {
+ if(this.active == ACTIVE_ACTIVE)
+ {
+ this.active = ACTIVE_NOT;
+ }
+ else
+ {
+ this.active = ACTIVE_ACTIVE;
+ }
+ }
+ else
+ {
+ this.active = act;
+ }
+
+ if (this.active != old_status)
+ {
+ this.SendFlags |= SF_LASER_UPDATE_ACTIVE;
+ misc_laser_aim(this);
+ }
}
-void laser_reset(entity this)
+void laser_use(entity this, entity actor, entity trigger)
{
- if(this.spawnflags & 1)
- this.state = 1;
- else
- this.state = 0;
+ this.setactive(this, ACTIVE_TOGGLE);
}
spawnfunc(misc_laser)
if(this.cnt < 0)
this.cnt = -1;
- if(this.colormod == '0 0 0')
+ if(!this.beam_color && this.colormod)
+ {
+ LOG_WARN("misc_laser uses legacy field 'colormod', please use 'beam_color' instead");
+ this.beam_color = this.colormod;
+ }
+
+ if(this.beam_color == '0 0 0')
+ {
if(!this.alpha)
- this.colormod = '1 0 0';
- if(this.message == "") this.message = "saw the light";
- if (this.message2 == "") this.message2 = "was pushed into a laser by";
- if(!this.scale) this.scale = 1;
- if(!this.modelscale) this.modelscale = 1;
- else if(this.modelscale < 0) this.modelscale = 0;
+ this.beam_color = '1 0 0';
+ }
+
+ if(this.message == "")
+ {
+ this.message = "saw the light";
+ }
+ if (this.message2 == "")
+ {
+ this.message2 = "was pushed into a laser by";
+ }
+ if(!this.scale)
+ {
+ this.scale = 1;
+ }
+ if(!this.modelscale)
+ {
+ this.modelscale = 1;
+ }
+ else if(this.modelscale < 0)
+ {
+ this.modelscale = 0;
+ }
setthink(this, misc_laser_think);
this.nextthink = time;
InitializeEntity(this, misc_laser_init, INITPRIO_FINDTARGET);
Net_LinkEntity(this, false, 0, laser_SendEntity);
+ this.setactive = laser_setactive;
+
IFTARGETED
{
- this.reset = laser_reset;
- this.reset(this);
+ // backwards compatibility
this.use = laser_use;
}
- else
- this.state = 1;
+
+ this.reset = generic_netlinked_reset;
+ this.reset(this);
}
#elif defined(CSQC)
// a laser goes from origin in direction angles
-// it has color 'colormod'
+// it has color 'beam_color'
// and stops when something is in the way
entityclass(Laser);
- class(Laser) .int cnt; // end effect
- class(Laser) .vector beam_color;
- class(Laser) .int active; // on-off
- class(Laser) .int count; // flags for the laser
- class(Laser) .vector velocity; // laser endpoint if it is FINITE
- class(Laser) .float alpha;
- class(Laser) .float scale; // scaling factor of the thickness
- class(Laser) .float modelscale; // scaling factor of the dlight
+ classfield(Laser) .int cnt; // end effect
+ classfield(Laser) .vector colormod;
+ classfield(Laser) .int state; // on-off
+ classfield(Laser) .int count; // flags for the laser
-classfield(Laser) .vector velocity;
++classfield(Laser) .vector velocity; // laser endpoint if it is FINITE
+ classfield(Laser) .float alpha;
+ classfield(Laser) .float scale; // scaling factor of the thickness
+ classfield(Laser) .float modelscale; // scaling factor of the dlight
void Draw_Laser(entity this)
{
- if(!this.state)
+ if(this.active == ACTIVE_NOT)
return;
InterpolateOrigin_Do(this);
- if(this.count & 0x80)
+ if(this.count & SF_LASER_FINITE)
{
- if(this.count & 0x10)
+ if(this.count & SF_LASER_NOTRACE)
{
trace_endpos = this.velocity;
trace_dphitq3surfaceflags = 0;
}
else
{
- if(this.count & 0x10)
+ if(this.count & SF_LASER_NOTRACE)
{
makevectors(this.angles);
- trace_endpos = this.origin + v_forward * 1048576;
+ trace_endpos = this.origin + v_forward * LASER_BEAM_MAXWORLDSIZE;
trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
}
else
{
makevectors(this.angles);
- traceline(this.origin, this.origin + v_forward * 32768, 0, this);
+ traceline(this.origin, this.origin + v_forward * LASER_BEAM_MAXLENGTH, 0, this);
if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
- trace_endpos = this.origin + v_forward * 1048576;
+ trace_endpos = this.origin + v_forward * LASER_BEAM_MAXWORLDSIZE;
}
}
if(this.scale != 0)
{
if(this.alpha)
{
- Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.colormod, this.alpha, DRAWFLAG_NORMAL, view_origin);
+ Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, this.alpha, DRAWFLAG_NORMAL, view_origin);
}
else
{
- Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.colormod, 0.5, DRAWFLAG_ADDITIVE, view_origin);
+ Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, 0.5, DRAWFLAG_ADDITIVE, view_origin);
}
}
if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
{
if(this.cnt >= 0)
__pointparticles(this.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
- if(this.colormod != '0 0 0' && this.modelscale != 0)
- adddynamiclight(trace_endpos + trace_plane_normal * 1, this.modelscale, this.colormod * 5);
+ if(this.beam_color != '0 0 0' && this.modelscale != 0)
+ adddynamiclight(trace_endpos + trace_plane_normal * 1, this.modelscale, this.beam_color * 5);
}
}
InterpolateOrigin_Undo(this);
// 30 bytes, or 13 bytes for just moving
- int f = ReadByte();
- this.count = (f & 0xF0);
+ int sendflags = ReadByte();
+ this.count = (sendflags & 0xF0);
- if(this.count & 0x80)
+ if(this.count & SF_LASER_FINITE)
this.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
else
this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
- if(f & 1)
+ if(sendflags & SF_LASER_UPDATE_ORIGIN)
{
this.origin = ReadVector();
setorigin(this, this.origin);
}
- if(f & 8)
+ if(sendflags & SF_LASER_UPDATE_EFFECT)
{
- this.colormod_x = ReadByte() / 255.0;
- this.colormod_y = ReadByte() / 255.0;
- this.colormod_z = ReadByte() / 255.0;
- if(f & 0x40)
+ this.beam_color.x = ReadByte() / 255.0;
+ this.beam_color.y = ReadByte() / 255.0;
+ this.beam_color.z = ReadByte() / 255.0;
+ if(sendflags & SF_LASER_ALPHA)
this.alpha = ReadByte() / 255.0;
else
this.alpha = 0;
- this.scale = 2;
- this.modelscale = 50;
- if(f & 0x20)
+ this.scale = 2; // NOTE: why 2?
+ this.modelscale = 50; // NOTE: why 50?
+ if(sendflags & SF_LASER_SCALE)
{
this.scale *= ReadByte() / 16.0; // beam radius
this.modelscale *= ReadByte() / 16.0; // dlight radius
}
- if((f & 0x80) || !(f & 0x10))
- this.cnt = ReadShort() - 1; // effect number
+ if((sendflags & SF_LASER_FINITE) || !(sendflags & SF_LASER_NOTRACE))
+ this.cnt = ReadShort(); // effect number
else
this.cnt = 0;
}
- if(f & 2)
+ if(sendflags & SF_LASER_UPDATE_TARGET)
{
- if(f & 0x80)
+ if(sendflags & SF_LASER_FINITE)
{
this.velocity = ReadVector();
}
this.angles_y = ReadAngle();
}
}
- if(f & 4)
- this.state = ReadByte();
+ if(sendflags & SF_LASER_UPDATE_ACTIVE)
+ this.active = ReadByte();
return = true;
#ifdef SVQC
-bool teleport_dest_send(entity this, entity to, int sf)
+bool teleport_dest_send(entity this, entity to, int sendflags)
{
WriteHeader(MSG_ENTITY, ENT_CLIENT_TELEPORT_DEST);
- WriteByte(MSG_ENTITY, sf);
+ WriteByte(MSG_ENTITY, sendflags);
- if(sf & 1)
+ if(sendflags & SF_TRIGGER_INIT)
{
WriteByte(MSG_ENTITY, this.cnt);
WriteCoord(MSG_ENTITY, this.speed);
void teleport_dest_link(entity this)
{
Net_LinkEntity(this, false, 0, teleport_dest_send);
- this.SendFlags |= 1; // update
+ this.SendFlags |= SF_TRIGGER_INIT;
}
spawnfunc(info_teleport_destination)
void teleport_dest_remove(entity this)
{
- //if(this.classname)
- //strunzone(this.classname);
- //this.classname = string_null;
-
- if(this.targetname)
- strunzone(this.targetname);
- this.targetname = string_null;
+ // strfree(this.classname);
+ strfree(this.targetname);
}
NET_HANDLE(ENT_CLIENT_TELEPORT_DEST, bool isnew)
{
- int sf = ReadByte();
+ int sendflags = ReadByte();
- if(sf & 1)
+ if(sendflags & SF_TRIGGER_INIT)
{
this.classname = "info_teleport_destination";
this.cnt = ReadByte();
#ifdef SVQC
IntrusiveList g_targetmusic_list;
-STATIC_INIT(g_targetmusic_list) { g_targetmusic_list = IL_NEW(); }
+STATIC_INIT(g_targetmusic_list)
+{
+ g_targetmusic_list = IL_NEW();
+}
// values:
// volume
}
void target_music_reset(entity this)
{
- if (this.targetname == "") target_music_sendto(this, MSG_ALL, 1);
+ if (this.targetname == "")
+ {
+ target_music_sendto(this, MSG_ALL, true);
+ }
}
void target_music_kill()
{
{
it.volume = 0;
if (it.targetname == "")
- target_music_sendto(it, MSG_ALL, 1);
+ target_music_sendto(it, MSG_ALL, true);
else
- target_music_sendto(it, MSG_ALL, 0);
+ target_music_sendto(it, MSG_ALL, false);
});
}
void target_music_use(entity this, entity actor, entity trigger)
if(IS_REAL_CLIENT(actor))
{
msg_entity = actor;
- target_music_sendto(this, MSG_ONE, 1);
+ target_music_sendto(this, MSG_ONE, true);
}
FOREACH_CLIENT(IS_SPEC(it) && it.enemy == actor, {
msg_entity = it;
- target_music_sendto(this, MSG_ONE, 1);
+ target_music_sendto(this, MSG_ONE, true);
});
}
spawnfunc(target_music)
this.volume = 1;
IL_PUSH(g_targetmusic_list, this);
if(this.targetname == "")
- target_music_sendto(this, MSG_INIT, 1);
+ target_music_sendto(this, MSG_INIT, true);
else
- target_music_sendto(this, MSG_INIT, 0);
+ target_music_sendto(this, MSG_INIT, false);
}
void TargetMusic_RestoreGame()
{
IL_EACH(g_targetmusic_list, true,
{
if(it.targetname == "")
- target_music_sendto(it, MSG_INIT, 1);
+ target_music_sendto(it, MSG_INIT, true);
else
- target_music_sendto(it, MSG_INIT, 0);
+ target_music_sendto(it, MSG_INIT, false);
});
}
// values:
// targetname
// fade_time
// spawnflags:
-// 1 = START_OFF
-// when triggered, it is disabled/enabled for everyone
-bool trigger_music_SendEntity(entity this, entity to, float sf)
+// START_DISABLED
+// can be disabled/enabled for everyone with relays
+bool trigger_music_SendEntity(entity this, entity to, int sendflags)
{
WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
- sf &= ~0x80;
- if(this.cnt)
- sf |= 0x80;
- WriteByte(MSG_ENTITY, sf);
- if(sf & 4)
+ WriteByte(MSG_ENTITY, sendflags);
+ if(sendflags & SF_MUSIC_ORIGIN)
{
WriteVector(MSG_ENTITY, this.origin);
}
- if(sf & 1)
+ if(sendflags & SF_TRIGGER_INIT)
{
if(this.model != "null")
{
WriteByte(MSG_ENTITY, this.fade_rate * 16.0);
WriteString(MSG_ENTITY, this.noise);
}
- return 1;
+ if(sendflags & SF_TRIGGER_UPDATE)
+ {
+ WriteByte(MSG_ENTITY, this.active);
+ }
+ return true;
}
void trigger_music_reset(entity this)
{
- this.cnt = !(this.spawnflags & 1);
- this.SendFlags |= 0x80;
-}
-void trigger_music_use(entity this, entity actor, entity trigger)
-{
- this.cnt = !this.cnt;
- this.SendFlags |= 0x80;
+ if(this.spawnflags & START_DISABLED)
+ {
+ this.setactive(this, ACTIVE_NOT);
+ }
+ else
+ {
+ this.setactive(this, ACTIVE_ACTIVE);
+ }
}
+
spawnfunc(trigger_music)
{
- if(this.model != "") _setmodel(this, this.model);
- if(!this.volume) this.volume = 1;
+ if(this.model != "")
+ {
+ _setmodel(this, this.model);
+ }
+ if(!this.volume)
+ {
+ this.volume = 1;
+ }
if(!this.modelindex)
{
setorigin(this, this.origin + this.mins);
setsize(this, '0 0 0', this.maxs - this.mins);
}
- trigger_music_reset(this);
- this.use = trigger_music_use;
+ this.setactive = generic_netlinked_setactive;
+ this.use = generic_netlinked_legacy_use; // backwards compatibility
this.reset = trigger_music_reset;
+ this.reset(this);
Net_LinkEntity(this, false, 0, trigger_music_SendEntity);
}
{
// run AFTER all the thinks!
entity best = music_default;
- if (music_target && time < music_target.lifetime) best = music_target;
- if (music_trigger) best = music_trigger;
+ if (music_target && time < music_target.lifetime)
+ {
+ best = music_target;
+ }
+ if (music_trigger)
+ {
+ best = music_trigger;
+ }
LL_EACH(TargetMusic_list, it.noise, {
const float vol0 = (getsoundtime(it, CH_BGM_SINGLE) >= 0) ? it.lastvol : -1;
if (it == best)
if (vol != vol0)
{
if(vol0 < 0)
- _sound(it, CH_BGM_SINGLE, it.noise, vol, ATTEN_NONE); // restart
+ sound7(it, CH_BGM_SINGLE, it.noise, vol, ATTEN_NONE, 0, BIT(4)); // restart
else
- _sound(it, CH_BGM_SINGLE, "", vol, ATTEN_NONE);
+ sound7(it, CH_BGM_SINGLE, "", vol, ATTEN_NONE, 0, BIT(4));
it.lastvol = vol;
}
});
}
if(e.noise != noi)
{
- if(e.noise)
- strunzone(e.noise);
- e.noise = strzone(noi);
+ strcpy(e.noise, noi);
precache_sound(e.noise);
_sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
if(getsoundtime(e, CH_BGM_SINGLE) < 0)
{
LOG_TRACEF("Cannot initialize sound %s", e.noise);
- strunzone(e.noise);
- e.noise = string_null;
+ strfree(e.noise);
}
}
e.volume = vol;
void Ent_TriggerMusic_Think(entity this)
{
- if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, this, NULL))
+ if(this.active == ACTIVE_NOT)
+ {
+ return;
+ }
+ vector org = (csqcplayer) ? csqcplayer.origin : view_origin;
+ if(WarpZoneLib_BoxTouchesBrush(org + STAT(PL_MIN), org + STAT(PL_MAX), this, NULL))
{
music_trigger = this;
}
- this.nextthink = time;
}
void Ent_TriggerMusic_Remove(entity this)
{
- if(this.noise)
- strunzone(this.noise);
- this.noise = string_null;
+ strfree(this.noise);
}
NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
{
- int f = ReadByte();
- if(f & 4)
+ int sendflags = ReadByte();
+ if(sendflags & SF_MUSIC_ORIGIN)
{
this.origin = ReadVector();
}
- if(f & 1)
+ if(sendflags & SF_TRIGGER_INIT)
{
this.modelindex = ReadShort();
if(this.modelindex)
this.fade_time = ReadByte() / 16.0;
this.fade_rate = ReadByte() / 16.0;
string s = this.noise;
- if(this.noise)
- strunzone(this.noise);
- this.noise = strzone(ReadString());
+ strcpy(this.noise, ReadString());
if(this.noise != s)
{
precache_sound(this.noise);
- _sound(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE);
+ sound7(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE, 0, BIT(4));
if(getsoundtime(this, CH_BGM_SINGLE) < 0)
{
- LOG_TRACEF("Cannot initialize sound %s", this.noise);
+ LOG_WARNF("Cannot initialize sound %s", this.noise);
- strunzone(this.noise);
- this.noise = string_null;
+ strfree(this.noise);
}
}
}
+ if(sendflags & SF_TRIGGER_UPDATE)
+ {
+ this.active = ReadByte();
+ }
setorigin(this, this.origin);
setsize(this, this.mins, this.maxs);
- this.cnt = 1;
- setthink(this, Ent_TriggerMusic_Think);
- this.nextthink = time;
+ this.draw = Ent_TriggerMusic_Think;
+ if(isnew)
+ {
+ LL_PUSH(TargetMusic_list, this);
+ IL_PUSH(g_drawables, this);
+ }
return true;
}
.float lifetime;
+const int SF_MUSIC_ORIGIN = BIT(2);
+
#ifdef CSQC
float music_disabled;
entity music_default;
// FIXME also control bgmvolume here, to not require a target_music for the default track.
entityclass(TargetMusic);
- class(TargetMusic) .int state;
- class(TargetMusic) .float lastvol;
+ classfield(TargetMusic) .int state;
+ classfield(TargetMusic) .float lastvol;
void TargetMusic_Advance();
#include "jumppads.qh"
// TODO: split target_push and put it in the target folder
#ifdef SVQC
-#include "jumppads.qh"
#include <common/physics/movetypes/movetypes.qh>
void trigger_push_use(entity this, entity actor, entity trigger)
if(teamplay)
{
this.team = actor.team;
- this.SendFlags |= 2;
+ this.SendFlags |= SF_TRIGGER_UPDATE;
}
}
#endif
return;
if(this.team)
- if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
+ if(((this.spawnflags & INVERT_TEAMS) == 0) == (DIFF_TEAM(this, toucher)))
return;
EXACTTRIGGER_TOUCH(this, toucher);
void trigger_push_updatelink(entity this)
{
- this.SendFlags |= 1;
+ this.SendFlags |= SF_TRIGGER_INIT;
}
void trigger_push_link(entity this)
target_push_init(this); // normal push target behaviour can be combined with a legacy pusher?
}
-spawnfunc(target_push) { target_push_init2(this); }
-spawnfunc(info_notnull) { target_push_init(this); }
-spawnfunc(target_position) { target_push_init(this); }
+spawnfunc(target_push)
+{
+ target_push_init2(this);
+}
+
+spawnfunc(info_notnull)
+{
+ target_push_init(this);
+}
+spawnfunc(target_position)
+{
+ target_push_init(this);
+}
#elif defined(CSQC)
NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH, bool isnew)
{
this.classname = "jumppad";
- int mytm = ReadByte(); if(mytm) { this.team = mytm - 1; }
+ int mytm = ReadByte();
+ if(mytm)
+ {
+ this.team = mytm - 1;
+ }
this.spawnflags = ReadInt24_t();
this.active = ReadByte();
this.height = ReadCoord();
void target_push_remove(entity this)
{
- //if(this.classname)
- //strunzone(this.classname);
- //this.classname = string_null;
-
- if(this.targetname)
- strunzone(this.targetname);
- this.targetname = string_null;
+ // strfree(this.classname);
+ strfree(this.targetname);
}
NET_HANDLE(ENT_CLIENT_TARGET_PUSH, bool isnew)
}
#ifdef SVQC
+void generic_setactive(entity this, int act)
+{
+ if(act == ACTIVE_TOGGLE)
+ {
+ if(this.active == ACTIVE_ACTIVE)
+ {
+ this.active = ACTIVE_NOT;
+ }
+ else
+ {
+ this.active = ACTIVE_ACTIVE;
+ }
+ }
+ else
+ {
+ this.active = act;
+ }
+}
+
+void generic_netlinked_setactive(entity this, int act)
+{
+ int old_status = this.active;
+ generic_setactive(this, act);
+
+ if (this.active != old_status)
+ {
+ this.SendFlags |= SF_TRIGGER_UPDATE;
+ }
+}
+
+void generic_netlinked_reset(entity this)
+{
+ IFTARGETED
+ {
+ if(this.spawnflags & START_ENABLED)
+ {
+ this.active = ACTIVE_ACTIVE;
+ }
+ else
+ {
+ this.active = ACTIVE_NOT;
+ }
+ }
+ else
+ {
+ this.active = ACTIVE_ACTIVE;
+ }
+
+ this.SendFlags |= SF_TRIGGER_UPDATE;
+}
+
+// Compatibility with old maps
+void generic_netlinked_legacy_use(entity this, entity actor, entity trigger)
+{
+ LOG_WARNF("Entity %s was (de)activated by a trigger, please update map to use relays", this.targetname);
+ this.setactive(this, ACTIVE_TOGGLE);
+}
bool autocvar_g_triggers_debug = true;
if(withtarget)
{
- if(this.target) { strunzone(this.target); }
- if(this.target2) { strunzone(this.target2); }
- if(this.target3) { strunzone(this.target3); }
- if(this.target4) { strunzone(this.target4); }
- if(this.targetname) { strunzone(this.targetname); }
- if(this.killtarget) { strunzone(this.killtarget); }
+ strfree(this.target);
+ strfree(this.target2);
+ strfree(this.target3);
+ strfree(this.target4);
+ strfree(this.targetname);
+ strfree(this.killtarget);
int targbits = ReadByte();
void trigger_remove_generic(entity this)
{
- if(this.target) { strunzone(this.target); }
- this.target = string_null;
-
- if(this.target2) { strunzone(this.target2); }
- this.target2 = string_null;
-
- if(this.target3) { strunzone(this.target3); }
- this.target3 = string_null;
-
- if(this.target4) { strunzone(this.target4); }
- this.target4 = string_null;
-
- if(this.targetname) { strunzone(this.targetname); }
- this.target = string_null;
-
- if(this.killtarget) { strunzone(this.killtarget); }
- this.killtarget = string_null;
+ strfree(this.target);
+ strfree(this.target2);
+ strfree(this.target3);
+ strfree(this.target4);
+ strfree(this.targetname);
+ strfree(this.killtarget);
}
#endif
#ifdef CSQC
#define REGISTER_NET_LINKED(id) \
- [[accumulate]] NET_HANDLE(id, bool isnew) \
+ ACCUMULATE NET_HANDLE(id, bool isnew) \
{ \
this = __self; \
this.sourceLoc = __FILE__ ":" STR(__LINE__); \
#ifdef SVQC
const int MSG_ENTITY = 5;
- .int Version; // deprecated, use SendFlags
.int SendFlags;
IntrusiveList g_uncustomizables;
{
if (g_buf == "") return;
localcmd("\ncmd c2s \"", strreplace("$", "$$", g_buf), "\"\n");
- strunzone(g_buf);
- g_buf = string_null;
+ strfree(g_buf);
}
#endif
string s = string_null;
yenc_single(b, s);
string tmp = strcat(g_buf, s);
- if (g_buf) strunzone(g_buf);
- g_buf = strzone(tmp);
+ strcpy(g_buf, tmp);
}
void WriteShort(int to, int b)
{
}
#define _spawnfunc_checktypes(fld) \
- if (fieldname == #fld) \
- if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", fieldname);
+ if (s == #fld) \
+ if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", s);
#else
#define _spawnfunc_checktypes(fld)
#endif
#define _spawnfunc_check(fld) \
- if (fieldname == #fld) continue;
+ if (s == #fld) continue;
noref int __spawnfunc_expecting;
noref entity __spawnfunc_expect;
#define spawnfunc_1(id) spawnfunc_2(id, FIELDS_UNION)
#define spawnfunc_2(id, whitelist) \
void __spawnfunc_##id(entity this); \
- [[accumulate]] void spawnfunc_##id(entity this) \
+ ACCUMULATE void spawnfunc_##id(entity this) \
{ \
if (!__spawnfunc_first) { \
__spawnfunc_first = true; \
if (!this.spawnfunc_checked) { \
for (int i = 0, n = numentityfields(); i < n; ++i) { \
string value = getentityfieldstring(i, this); \
- string fieldname = entityfieldname(i); \
+ string s = entityfieldname(i); \
whitelist(_spawnfunc_checktypes) \
if (value == "") continue; \
- if (fieldname == "") continue; \
+ if (s == "") continue; \
FIELDS_COMMON(_spawnfunc_check) \
whitelist(_spawnfunc_check) \
- LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, fieldname, value); \
+ LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, s, value); \
} \
this.spawnfunc_checked = true; \
if (this) { \
FIELD_SCALAR(fld, bgmscriptsustain) \
FIELD_SCALAR(fld, bgmscript) \
FIELD_SCALAR(fld, button0) \
+ FIELD_SCALAR(fld, chmap) \
FIELD_SCALAR(fld, cnt) \
FIELD_SCALAR(fld, colormap) \
FIELD_SCALAR(fld, count) \
FIELD_SCALAR(fld, dmg_force) \
FIELD_SCALAR(fld, dmg_radius) \
FIELD_SCALAR(fld, effects) \
+ FIELD_SCALAR(fld, falloff) \
FIELD_SCALAR(fld, flags) \
FIELD_SCALAR(fld, fog) \
FIELD_SCALAR(fld, frags) \
FIELD_SCALAR(fld, frame) \
+ FIELD_SCALAR(fld, gametype) \
FIELD_SCALAR(fld, gametypefilter) \
FIELD_SCALAR(fld, geomtype) \
FIELD_SCALAR(fld, gravity) \
FIELD_SCALAR(fld, noalign) \
FIELD_SCALAR(fld, noise1) \
FIELD_SCALAR(fld, noise2) \
+ FIELD_SCALAR(fld, noise3) \
FIELD_SCALAR(fld, noise) \
FIELD_SCALAR(fld, phase) \
FIELD_SCALAR(fld, platmovetype) \
FIELD_SCALAR(fld, target_random) \
FIELD_SCALAR(fld, target_range) \
FIELD_SCALAR(fld, team) \
+ FIELD_SCALAR(fld, trigger_reverse) \
FIELD_SCALAR(fld, turret_scale_health) \
FIELD_SCALAR(fld, turret_scale_range) \
FIELD_SCALAR(fld, turret_scale_respawn) \
FIELD_VEC(fld, absmin) \
FIELD_VEC(fld, angles) \
FIELD_VEC(fld, avelocity) \
+ FIELD_VEC(fld, beam_color)\
FIELD_VEC(fld, debrisavelocityjitter) \
FIELD_VEC(fld, debrisvelocity) \
FIELD_VEC(fld, debrisvelocityjitter) \
FIELD_VEC(fld, color) \
FIELD_VEC(fld, mangle) \
FIELD_VEC(fld, maxs) \
- FIELD_VEC(fld, maxs) \
FIELD_VEC(fld, mins) \
FIELD_VEC(fld, modelscale_vec) \
FIELD_VEC(fld, velocity) \