]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
More fun stuff
authorMario <zacjardine@y7mail.com>
Fri, 30 Jan 2015 10:08:20 +0000 (21:08 +1100)
committerMario <zacjardine@y7mail.com>
Fri, 30 Jan 2015 10:08:20 +0000 (21:08 +1100)
19 files changed:
qcsrc/common/triggers/func/breakable.qc [new file with mode: 0644]
qcsrc/common/triggers/func/include.qc
qcsrc/common/triggers/target/include.qc
qcsrc/common/triggers/target/music.qc [new file with mode: 0644]
qcsrc/common/triggers/target/spawn.qc [new file with mode: 0644]
qcsrc/common/triggers/trigger/include.qc
qcsrc/common/triggers/trigger/include.qh
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/triggers/trigger/jumppads.qh
qcsrc/common/triggers/trigger/relay_if.qc [new file with mode: 0644]
qcsrc/common/triggers/trigger/secret.qc [new file with mode: 0644]
qcsrc/common/triggers/trigger/secret.qh [new file with mode: 0644]
qcsrc/server/func_breakable.qc [deleted file]
qcsrc/server/progs.src
qcsrc/server/secret.qc [deleted file]
qcsrc/server/secret.qh [deleted file]
qcsrc/server/target_music.qc [deleted file]
qcsrc/server/target_spawn.qc [deleted file]
qcsrc/warpzonelib/common.qc

diff --git a/qcsrc/common/triggers/func/breakable.qc b/qcsrc/common/triggers/func/breakable.qc
new file mode 100644 (file)
index 0000000..c3890d1
--- /dev/null
@@ -0,0 +1,288 @@
+#ifdef SVQC
+.entity sprite;
+
+.float dmg;
+.float dmg_edge;
+.float dmg_radius;
+.float dmg_force;
+.float debrismovetype;
+.float debrissolid;
+.vector debrisvelocity;
+.vector debrisvelocityjitter;
+.vector debrisavelocityjitter;
+.float debristime;
+.float debristimejitter;
+.float debrisfadetime;
+.float debrisdamageforcescale;
+.float debrisskin;
+
+.string mdl_dead; // or "" to hide when broken
+.string debris; // space separated list of debris models
+// other fields:
+//   mdl = particle effect name
+//   count = particle effect multiplier
+//   targetname = target to trigger to unbreak the model
+//   target = targets to trigger when broken
+//   health = amount of damage it can take
+//   spawnflags:
+//     1 = start disabled (needs to be triggered to activate)
+//     2 = indicate damage
+// notes:
+//   for mdl_dead to work, origin must be set (using a common/origin brush).
+//   Otherwise mdl_dead will be displayed at the map origin, and nobody would
+//   want that!
+
+void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
+
+//
+// func_breakable
+// - basically func_assault_destructible for general gameplay use
+//
+void LaunchDebris (string debrisname, vector force)
+{
+       local   entity dbr;
+
+       dbr = spawn();
+       setorigin(dbr, self.absmin
+                  + '1 0 0' * random() * (self.absmax_x - self.absmin_x)
+                  + '0 1 0' * random() * (self.absmax_y - self.absmin_y)
+                  + '0 0 1' * random() * (self.absmax_z - self.absmin_z));
+       setmodel (dbr, debrisname );
+       dbr.skin = self.debrisskin;
+       dbr.colormap = self.colormap; // inherit team colors
+       dbr.owner = self; // do not be affected by our own explosion
+       dbr.movetype = self.debrismovetype;
+       dbr.solid = self.debrissolid;
+       if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
+               setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
+       dbr.velocity_x = self.debrisvelocity_x + self.debrisvelocityjitter_x * crandom();
+       dbr.velocity_y = self.debrisvelocity_y + self.debrisvelocityjitter_y * crandom();
+       dbr.velocity_z = self.debrisvelocity_z + self.debrisvelocityjitter_z * crandom();
+       self.velocity = self.velocity + force * self.debrisdamageforcescale;
+       dbr.avelocity_x = random()*self.debrisavelocityjitter_x;
+       dbr.avelocity_y = random()*self.debrisavelocityjitter_y;
+       dbr.avelocity_z = random()*self.debrisavelocityjitter_z;
+       dbr.damageforcescale = self.debrisdamageforcescale;
+       if(dbr.damageforcescale)
+               dbr.takedamage = DAMAGE_YES;
+       SUB_SetFade(dbr, time + self.debristime + crandom() * self.debristimejitter, self.debrisfadetime);
+}
+
+void func_breakable_colormod()
+{
+       float h;
+       if (!(self.spawnflags & 2))
+               return;
+       h = self.health / self.max_health;
+       if(h < 0.25)
+               self.colormod = '1 0 0';
+       else if(h <= 0.75)
+               self.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
+       else
+               self.colormod = '1 1 1';
+               
+       CSQCMODEL_AUTOUPDATE();
+}
+
+void func_breakable_look_destroyed()
+{
+       float floor_z;
+
+       if(self.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
+               self.dropped_origin = self.origin;
+
+       if(self.mdl_dead == "")
+               self.model = "";
+       else {
+               if (self.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..
+                       floor_z = self.absmin_z;
+                       setorigin(self,((self.absmax+self.absmin)*.5));
+                       self.origin_z = floor_z;
+               }
+               setmodel(self, self.mdl_dead);
+       }
+
+       self.solid = SOLID_NOT;
+}
+
+void func_breakable_look_restore()
+{
+       setmodel(self, self.mdl);
+       if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
+               setorigin(self, self.dropped_origin);
+       self.solid = SOLID_BSP;
+}
+
+void func_breakable_behave_destroyed()
+{
+       self.health = self.max_health;
+       self.takedamage = DAMAGE_NO;
+       self.bot_attack = FALSE;
+       self.event_damage = func_null;
+       self.state = 1;
+       func_breakable_colormod();
+}
+
+void func_breakable_behave_restore()
+{
+       self.health = self.max_health;
+       if(self.sprite)
+       {
+               WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
+               WaypointSprite_UpdateHealth(self.sprite, self.health);
+       }
+       self.takedamage = DAMAGE_AIM;
+       self.bot_attack = TRUE;
+       self.event_damage = func_breakable_damage;
+       self.state = 0;
+       self.nextthink = 0; // cancel auto respawn
+       func_breakable_colormod();
+}
+
+void func_breakable_destroyed()
+{
+       func_breakable_look_destroyed();
+       func_breakable_behave_destroyed();
+       
+       CSQCMODEL_AUTOUPDATE();
+}
+
+void func_breakable_restore()
+{
+       func_breakable_look_restore();
+       func_breakable_behave_restore();
+       
+       CSQCMODEL_AUTOUPDATE();
+}
+
+vector debrisforce; // global, set before calling this
+void func_breakable_destroy() {
+       float n, i;
+       string oldmsg;
+
+       activator = self.owner;
+       self.owner = world; // set by W_PrepareExplosionByDamage
+
+       // now throw around the debris
+       n = tokenize_console(self.debris);
+       for(i = 0; i < n; ++i)
+               LaunchDebris(argv(i), debrisforce);
+
+       func_breakable_destroyed();
+
+       if(self.noise)
+               sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+
+       if(self.dmg)
+               RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER, world);
+
+       if(self.cnt)
+               pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
+
+       if(self.respawntime)
+       {
+               self.think = func_breakable_restore;
+               self.nextthink = time + self.respawntime + crandom() * self.respawntimejitter;
+       }
+
+       oldmsg = self.message;
+       self.message = "";
+       SUB_UseTargets();
+       self.message = oldmsg;
+}
+
+void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       if(self.state == 1)
+               return;
+       if(self.spawnflags & DOOR_NOSPLASH)
+               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+                       return;
+       if(self.team)
+               if(attacker.team == self.team)
+                       return;
+       self.health = self.health - damage;
+       if(self.sprite)
+       {
+               WaypointSprite_Ping(self.sprite);
+               WaypointSprite_UpdateHealth(self.sprite, self.health);
+       }
+       func_breakable_colormod();
+
+       if(self.health <= 0)
+       {
+               debrisforce = force;
+               W_PrepareExplosionByDamage(attacker, func_breakable_destroy);
+       }
+}
+
+void func_breakable_reset()
+{
+       self.team = self.team_saved;
+       func_breakable_look_restore();
+       if(self.spawnflags & 1)
+               func_breakable_behave_destroyed();
+       else
+               func_breakable_behave_restore();
+               
+       CSQCMODEL_AUTOUPDATE();
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+void spawnfunc_func_breakable() {
+       float n, i;
+       if(!self.health)
+               self.health = 100;
+       self.max_health = self.health;
+
+       // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
+       if(!self.debrismovetype) self.debrismovetype = MOVETYPE_BOUNCE;
+       if(!self.debrissolid) self.debrissolid = SOLID_NOT;
+       if(self.debrisvelocity == '0 0 0') self.debrisvelocity = '0 0 140';
+       if(self.debrisvelocityjitter == '0 0 0') self.debrisvelocityjitter = '70 70 70';
+       if(self.debrisavelocityjitter == '0 0 0') self.debrisavelocityjitter = '600 600 600';
+       if(!self.debristime) self.debristime = 3.5;
+       if(!self.debristimejitter) self.debristime = 2.5;
+
+       if(self.mdl != "")
+               self.cnt = particleeffectnum(self.mdl);
+       if(self.count == 0)
+               self.count = 1;
+
+       if(self.message == "")
+               self.message = "got too close to an explosion";
+       if(self.message2 == "")
+               self.message2 = "was pushed into an explosion by";
+       if(!self.dmg_radius)
+               self.dmg_radius = 150;
+       if(!self.dmg_force)
+               self.dmg_force = 200;
+
+       self.mdl = self.model;
+       SetBrushEntityModel();
+
+       self.use = func_breakable_restore;
+
+       // precache all the models
+       if (self.mdl_dead)
+               precache_model(self.mdl_dead);
+       n = tokenize_console(self.debris);
+       for(i = 0; i < n; ++i)
+               precache_model(argv(i));
+       if(self.noise)
+               precache_sound(self.noise);
+
+       self.team_saved = self.team;
+       self.dropped_origin = self.origin;
+
+       self.reset = func_breakable_reset;
+       func_breakable_reset();
+       
+       CSQCMODEL_AUTOINIT();
+}
+
+// for use in maps with a "model" key set
+void spawnfunc_misc_breakablemodel() {
+       spawnfunc_func_breakable();
+}
+#endif
index 4fad7b4129d4dd51d77ab2e53aa5af6d2e0f99b3..dc03693537121ffb699b4a5440426abe8fb09325 100644 (file)
@@ -1,4 +1,5 @@
 #include "bobbing.qc"
+#include "breakable.qc"
 #include "button.qc"
 #include "conveyor.qc"
 #include "door.qc"
index 43e4741cb0daa97ed377d6881b6d0085227bc62d..a8c876b9cd4a8dd6332605a590b9617a2dee1ca5 100644 (file)
@@ -1,3 +1,5 @@
 #include "changelevel.qc"
+#include "music.qc"
+#include "spawn.qc"
 #include "speaker.qc"
 #include "voicescript.qc"
diff --git a/qcsrc/common/triggers/target/music.qc b/qcsrc/common/triggers/target/music.qc
new file mode 100644 (file)
index 0000000..5aa095d
--- /dev/null
@@ -0,0 +1,136 @@
+#ifdef SVQC
+.float lifetime;
+// values:
+//   volume
+//   noise
+//   targetname
+//   lifetime
+//   fade_time
+//   fade_rate
+// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
+// when targetname is not set, THIS ONE is default
+void target_music_sendto(float to, float is)
+{
+       WriteByte(to, SVC_TEMPENTITY);
+       WriteByte(to, TE_CSQC_TARGET_MUSIC);
+       WriteShort(to, num_for_edict(self));
+       WriteByte(to, self.volume * 255.0 * is);
+       WriteByte(to, self.fade_time * 16.0);
+       WriteByte(to, self.fade_rate * 16.0);
+       WriteByte(to, self.lifetime);
+       WriteString(to, self.noise);
+}
+void target_music_reset()
+{
+       if(self.targetname == "")
+               target_music_sendto(MSG_ALL, 1);
+}
+void target_music_use()
+{
+       if(!activator)
+               return;
+       if(IS_REAL_CLIENT(activator))
+       {
+               msg_entity = activator;
+               target_music_sendto(MSG_ONE, 1);
+       }
+       entity head;
+       FOR_EACH_SPEC(head) if(head.enemy == activator) { msg_entity = head; target_music_sendto(MSG_ONE, 1); }
+}
+void spawnfunc_target_music()
+{
+       self.use = target_music_use;
+       self.reset = target_music_reset;
+       if(!self.volume)
+               self.volume = 1;
+       if(self.targetname == "")
+               target_music_sendto(MSG_INIT, 1);
+       else
+               target_music_sendto(MSG_INIT, 0);
+}
+void TargetMusic_RestoreGame()
+{
+       for(self = world; (self = find(self, classname, "target_music")); )
+       {
+               if(self.targetname == "")
+                       target_music_sendto(MSG_INIT, 1);
+               else
+                       target_music_sendto(MSG_INIT, 0);
+       }
+}
+// values:
+//   volume
+//   noise
+//   targetname
+//   fade_time
+// spawnflags:
+//   1 = START_OFF
+// when triggered, it is disabled/enabled for everyone
+float trigger_music_SendEntity(entity to, float sf)
+{
+       WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
+       sf &= ~0x80;
+       if(self.cnt)
+               sf |= 0x80;
+       WriteByte(MSG_ENTITY, sf);
+       if(sf & 4)
+       {
+               WriteCoord(MSG_ENTITY, self.origin_x);
+               WriteCoord(MSG_ENTITY, self.origin_y);
+               WriteCoord(MSG_ENTITY, self.origin_z);
+       }
+       if(sf & 1)
+       {
+               if(self.model != "null")
+               {
+                       WriteShort(MSG_ENTITY, self.modelindex);
+                       WriteCoord(MSG_ENTITY, self.mins_x);
+                       WriteCoord(MSG_ENTITY, self.mins_y);
+                       WriteCoord(MSG_ENTITY, self.mins_z);
+                       WriteCoord(MSG_ENTITY, self.maxs_x);
+                       WriteCoord(MSG_ENTITY, self.maxs_y);
+                       WriteCoord(MSG_ENTITY, self.maxs_z);
+               }
+               else
+               {
+                       WriteShort(MSG_ENTITY, 0);
+                       WriteCoord(MSG_ENTITY, self.maxs_x);
+                       WriteCoord(MSG_ENTITY, self.maxs_y);
+                       WriteCoord(MSG_ENTITY, self.maxs_z);
+               }
+               WriteByte(MSG_ENTITY, self.volume * 255.0);
+               WriteByte(MSG_ENTITY, self.fade_time * 16.0);
+               WriteByte(MSG_ENTITY, self.fade_rate * 16.0);
+               WriteString(MSG_ENTITY, self.noise);
+       }
+       return 1;
+}
+void trigger_music_reset()
+{
+       self.cnt = !(self.spawnflags & 1);
+       self.SendFlags |= 0x80;
+}
+void trigger_music_use()
+{
+       self.cnt = !self.cnt;
+       self.SendFlags |= 0x80;
+}
+void spawnfunc_trigger_music()
+{
+       if(self.model != "")
+               setmodel(self, self.model);
+       if(!self.volume)
+               self.volume = 1;
+       if(!self.modelindex)
+       {
+               setorigin(self, self.origin + self.mins);
+               setsize(self, '0 0 0', self.maxs - self.mins);
+       }
+       trigger_music_reset();
+
+       self.use = trigger_music_use;
+       self.reset = trigger_music_reset;
+
+       Net_LinkEntity(self, FALSE, 0, trigger_music_SendEntity);
+}
+#endif
diff --git a/qcsrc/common/triggers/target/spawn.qc b/qcsrc/common/triggers/target/spawn.qc
new file mode 100644 (file)
index 0000000..d661b98
--- /dev/null
@@ -0,0 +1,337 @@
+#ifdef SVQC
+// spawner entity
+// "classname" "target_spawn"
+// "message" "fieldname value fieldname value ..."
+// "spawnflags"
+//   1 = call the spawn function
+//   2 = trigger on map load
+
+float target_spawn_initialized;
+.void() target_spawn_spawnfunc;
+float target_spawn_spawnfunc_field;
+.entity target_spawn_activator;
+.float target_spawn_id;
+float target_spawn_count;
+
+void target_spawn_helper_setmodel()
+{
+       setmodel(self, self.model);
+}
+
+void target_spawn_helper_setsize()
+{
+       setsize(self, self.mins, self.maxs);
+}
+
+void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act)
+{
+       float i, n, valuefieldpos;
+       string key, value, valuefield, valueoffset, valueoffsetrandom;
+       entity valueent;
+       vector data, data2;
+       entity oldself;
+       entity oldactivator;
+
+       n = tokenize_console(msg);
+
+       for(i = 0; i < n-1; i += 2)
+       {
+               key = argv(i);
+               value = argv(i+1);
+               if(key == "$")
+               {
+                       data_x = -1;
+                       data_y = FIELD_STRING;
+               }
+               else
+               {
+                       data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
+                       if(data_y == 0) // undefined field, i.e., invalid type
+                       {
+                               print("target_spawn: invalid/unknown entity key ", key, " specified, ignored!\n");
+                               continue;
+                       }
+               }
+               if(substring(value, 0, 1) == "$")
+               {
+                       value = substring(value, 1, strlen(value) - 1);
+                       if(substring(value, 0, 1) == "$")
+                       {
+                               // deferred replacement
+                               // do nothing
+                               // useful for creating target_spawns with this!
+                       }
+                       else
+                       {
+                               // replace me!
+                               valuefieldpos = strstrofs(value, "+", 0);
+                               valueoffset = "";
+                               if(valuefieldpos != -1)
+                               {
+                                       valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
+                                       value = substring(value, 0, valuefieldpos);
+                               }
+
+                               valuefieldpos = strstrofs(valueoffset, "+", 0);
+                               valueoffsetrandom = "";
+                               if(valuefieldpos != -1)
+                               {
+                                       valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
+                                       valueoffset = substring(valueoffset, 0, valuefieldpos);
+                               }
+
+                               valuefieldpos = strstrofs(value, ".", 0);
+                               valuefield = "";
+                               if(valuefieldpos != -1)
+                               {
+                                       valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
+                                       value = substring(value, 0, valuefieldpos);
+                               }
+
+                               if(value == "self")
+                               {
+                                       valueent = self;
+                                       value = "";
+                               }
+                               else if(value == "activator")
+                               {
+                                       valueent = act;
+                                       value = "";
+                               }
+                               else if(value == "other")
+                               {
+                                       valueent = other;
+                                       value = "";
+                               }
+                               else if(value == "pusher")
+                               {
+                                       if(time < act.pushltime)
+                                               valueent = act.pusher;
+                                       else
+                                               valueent = world;
+                                       value = "";
+                               }
+                               else if(value == "target")
+                               {
+                                       valueent = e;
+                                       value = "";
+                               }
+                               else if(value == "killtarget")
+                               {
+                                       valueent = kt;
+                                       value = "";
+                               }
+                               else if(value == "target2")
+                               {
+                                       valueent = t2;
+                                       value = "";
+                               }
+                               else if(value == "target3")
+                               {
+                                       valueent = t3;
+                                       value = "";
+                               }
+                               else if(value == "target4")
+                               {
+                                       valueent = t4;
+                                       value = "";
+                               }
+                               else if(value == "time")
+                               {
+                                       valueent = world;
+                                       value = ftos(time);
+                               }
+                               else
+                               {
+                                       print("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!\n");
+                                       continue;
+                               }
+
+                               if(valuefield == "")
+                               {
+                                       if(value == "")
+                                               value = ftos(num_for_edict(valueent));
+                               }
+                               else
+                               {
+                                       if(value != "")
+                                       {
+                                               print("target_spawn: try to get a field of a non-entity, ignored!\n");
+                                               continue;
+                                       }
+                                       data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
+                                       if(data2_y == 0) // undefined field, i.e., invalid type
+                                       {
+                                               print("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!\n");
+                                               continue;
+                                       }
+                                       value = getentityfieldstring(data2_x, valueent);
+                               }
+
+                               if(valueoffset != "")
+                               {
+                                       switch(data_y)
+                                       {
+                                               case FIELD_STRING:
+                                                       value = strcat(value, valueoffset);
+                                                       break;
+                                               case FIELD_FLOAT:
+                                                       value = ftos(stof(value) + stof(valueoffset));
+                                                       break;
+                                               case FIELD_VECTOR:
+                                                       value = vtos(stov(value) + stov(valueoffset));
+                                                       break;
+                                               default:
+                                                       print("target_spawn: only string, float and vector fields can do calculations, calculation ignored!\n");
+                                                       break;
+                                       }
+                               }
+
+                               if(valueoffsetrandom != "")
+                               {
+                                       switch(data_y)
+                                       {
+                                               case FIELD_FLOAT:
+                                                       value = ftos(stof(value) + random() * stof(valueoffsetrandom));
+                                                       break;
+                                               case FIELD_VECTOR:
+                                                       data2 = stov(valueoffsetrandom);
+                                                       value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
+                                                       break;
+                                               default:
+                                                       print("target_spawn: only float and vector fields can do random calculations, calculation ignored!\n");
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+               if(key == "$")
+               {
+                       if(substring(value, 0, 1) == "_")
+                               value = strcat("target_spawn_helper", value);
+                       putentityfieldstring(target_spawn_spawnfunc_field, e, value);
+
+                       oldself = self;
+                       oldactivator = activator;
+
+                       self = e;
+                       activator = act;
+
+                       self.target_spawn_spawnfunc();
+
+                       self = oldself;
+                       activator = oldactivator;
+               }
+               else
+               {
+                       if(data_y == FIELD_VECTOR)
+                               value = strreplace("'", "", value); // why?!?
+                       putentityfieldstring(data_x, e, value);
+               }
+       }
+}
+
+void target_spawn_useon(entity e)
+{
+       self.target_spawn_activator = activator;
+       target_spawn_edit_entity(
+               e,
+               self.message,
+               find(world, targetname, self.killtarget),
+               find(world, targetname, self.target2),
+               find(world, targetname, self.target3),
+               find(world, targetname, self.target4),
+               activator
+       );
+}
+
+float target_spawn_cancreate()
+{
+       float c;
+       entity e;
+
+       c = self.count;
+       if(c == 0) // no limit?
+               return 1;
+
+       ++c; // increase count to not include MYSELF
+       for(e = world; (e = findfloat(e, target_spawn_id, self.target_spawn_id)); --c)
+               ;
+
+       // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
+       if(c == 0)
+               return 0;
+       return 1;
+}
+
+void target_spawn_use()
+{
+       entity e;
+
+       if(self.target == "")
+       {
+               // spawn new entity
+               if(!target_spawn_cancreate())
+                       return;
+               e = spawn();
+               target_spawn_useon(e);
+               e.target_spawn_id = self.target_spawn_id;
+       }
+       else if(self.target == "*activator")
+       {
+               // edit entity
+               if(activator)
+                       target_spawn_useon(activator);
+       }
+       else
+       {
+               // edit entity
+               for(e = world; (e = find(e, targetname, self.target)); )
+                       target_spawn_useon(e);
+       }
+}
+
+void target_spawn_spawnfirst()
+{
+       activator = self.target_spawn_activator;
+       if(self.spawnflags & 2)
+               target_spawn_use();
+}
+
+void initialize_field_db()
+{
+       if(!target_spawn_initialized)
+       {
+               float n, i;
+               string fn;
+               vector prev, new;
+               float ft;
+
+               n = numentityfields();
+               for(i = 0; i < n; ++i)
+               {
+                       fn = entityfieldname(i);
+                       ft = entityfieldtype(i);
+                       new = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
+                       prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
+                       if(prev_y == 0)
+                       {
+                               db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(new));
+                               if(fn == "target_spawn_spawnfunc")
+                                       target_spawn_spawnfunc_field = i;
+                       }
+               }
+
+               target_spawn_initialized = 1;
+       }
+}
+
+void spawnfunc_target_spawn()
+{
+       initialize_field_db();
+       self.use = target_spawn_use;
+       self.message = strzone(strreplace("'", "\"", self.message));
+       self.target_spawn_id = ++target_spawn_count;
+       InitializeEntity(self, target_spawn_spawnfirst, INITPRIO_LAST);
+}
+#endif
index 0de1d26d6e8458d1b806b17657ecefca1e2c3c85..5a0e83f5ae43b2157f9041aedb5dad92bdacd381 100644 (file)
@@ -14,5 +14,7 @@
 #include "multivibrator.qc"
 #include "relay.qc"
 #include "relay_activators.qc"
+#include "relay_if.qc"
 #include "relay_teamcheck.qc"
+#include "secret.qc"
 #include "swamp.qc"
index dd841de1423886321eac793d99503de4d37c3b3b..5ec31751cadc65e54a850e943133261d05622037 100644 (file)
@@ -1,3 +1,4 @@
 #include "multi.qh"
 #include "jumppads.qh"
+#include "secret.qh"
 #include "swamp.qh"
index f2074f031e92faba1e4e9ba26fc1840abd89abe8..67fd6a91df81fc6127ed755c45202595daf66a1c 100644 (file)
@@ -2,14 +2,6 @@
 
 #ifdef SVQC
 
-const float PUSH_ONCE = 1;
-const float PUSH_SILENT = 2;
-
-.float pushltime;
-.float istypefrag;
-
-void() SUB_UseTargets;
-
 void trigger_push_use()
 {
        if(teamplay)
index 2c5363b5975223bd15b003fa649074157ba56db8..6330dc3c4f83cbc00794479d76eca6d5ba35ae94 100644 (file)
@@ -2,3 +2,11 @@
 void ent_trigger_push();
 void ent_target_push();
 #endif
+
+const float PUSH_ONCE = 1;
+const float PUSH_SILENT = 2;
+
+.float pushltime;
+.float istypefrag;
+
+void() SUB_UseTargets;
diff --git a/qcsrc/common/triggers/trigger/relay_if.qc b/qcsrc/common/triggers/trigger/relay_if.qc
new file mode 100644 (file)
index 0000000..ade56c1
--- /dev/null
@@ -0,0 +1,20 @@
+#ifdef SVQC
+void trigger_relay_if_use()
+{
+       float n;
+       n = self.count;
+
+       // TODO make this generic AND faster than nextent()ing through all, if somehow possible
+       n = (cvar_string(self.netname) == cvar_string(self.message));
+       if(self.spawnflags & 1)
+               n = !n;
+
+       if(n)
+               SUB_UseTargets();
+}
+
+void spawnfunc_trigger_relay_if()
+{
+       self.use = trigger_relay_if_use;
+}
+#endif
diff --git a/qcsrc/common/triggers/trigger/secret.qc b/qcsrc/common/triggers/trigger/secret.qc
new file mode 100644 (file)
index 0000000..48dc360
--- /dev/null
@@ -0,0 +1,75 @@
+#ifdef SVQC
+void secrets_setstatus() {
+       self.stat_secrets_total = secrets_total;
+       self.stat_secrets_found = secrets_found;
+}
+
+/**
+ * A secret has been found (maybe :P)
+ */
+void trigger_secret_touch() {
+       // only a player can trigger this
+       if (!IS_PLAYER(other))
+               return;
+
+       // update secrets found counter
+       secrets_found += 1;
+       //print("Secret found: ", ftos(secret_counter.cnt), "/");
+       //print(ftos(secret_counter.count), "\n");
+
+       // centerprint message (multi_touch() doesn't always call centerprint())
+       centerprint(other, self.message);
+       self.message = "";
+
+       // handle normal trigger features
+       multi_touch();
+       remove(self);
+}
+
+/*QUAKED trigger_secret (.5 .5 .5) ?
+Variable sized secret trigger. Can be targeted at one or more entities.
+Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
+-------- KEYS --------
+sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
+noise: path to sound file, if you want to play something else
+target: trigger all entities with this targetname when triggered
+message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
+killtarget: remove all entities with this targetname when triggered
+-------- NOTES --------
+You should create a common/trigger textured brush covering the entrance to a secret room/area.
+Trigger secret can only be trigger by a player's touch and can not be a target itself.
+*/
+void spawnfunc_trigger_secret() {
+       // FIXME: should it be disabled in most modes?
+
+       // update secrets count
+       secrets_total += 1;
+
+       // add default message
+       if (self.message == "")
+               self.message = "You found a secret!";
+
+       // set default sound
+       if (self.noise == "")
+       if (!self.sounds)
+               self.sounds = 1; // misc/secret.wav
+
+       // this entity can't be a target itself!!!!
+       self.targetname = "";
+
+       // you can't just shoot a room to find it, can you?
+       self.health = 0;
+
+       // a secret can not be delayed
+       self.delay = 0;
+
+       // convert this trigger to trigger_once
+       self.classname = "trigger_once";
+       spawnfunc_trigger_once();
+
+       // take over the touch() function, so we can mark secret as found
+       self.touch = trigger_secret_touch;
+       // ignore triggering;
+       self.use = func_null;
+}
+#endif
diff --git a/qcsrc/common/triggers/trigger/secret.qh b/qcsrc/common/triggers/trigger/secret.qh
new file mode 100644 (file)
index 0000000..e289f57
--- /dev/null
@@ -0,0 +1,20 @@
+#ifdef SVQC
+/**
+ * Total number of secrets on the map.
+ */
+float secrets_total;
+
+/**
+ * Total numbe of secrets found on the map.
+ */
+float secrets_found;
+
+
+.float stat_secrets_total;
+.float stat_secrets_found;
+
+/**
+ * update secrets status.
+ */
+void secrets_setstatus();
+#endif
diff --git a/qcsrc/server/func_breakable.qc b/qcsrc/server/func_breakable.qc
deleted file mode 100644 (file)
index 0bf7105..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-.entity sprite;
-
-.float dmg;
-.float dmg_edge;
-.float dmg_radius;
-.float dmg_force;
-.float debrismovetype;
-.float debrissolid;
-.vector debrisvelocity;
-.vector debrisvelocityjitter;
-.vector debrisavelocityjitter;
-.float debristime;
-.float debristimejitter;
-.float debrisfadetime;
-.float debrisdamageforcescale;
-.float debrisskin;
-
-.string mdl_dead; // or "" to hide when broken
-.string debris; // space separated list of debris models
-// other fields:
-//   mdl = particle effect name
-//   count = particle effect multiplier
-//   targetname = target to trigger to unbreak the model
-//   target = targets to trigger when broken
-//   health = amount of damage it can take
-//   spawnflags:
-//     1 = start disabled (needs to be triggered to activate)
-//     2 = indicate damage
-// notes:
-//   for mdl_dead to work, origin must be set (using a common/origin brush).
-//   Otherwise mdl_dead will be displayed at the map origin, and nobody would
-//   want that!
-
-void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
-
-//
-// func_breakable
-// - basically func_assault_destructible for general gameplay use
-//
-void LaunchDebris (string debrisname, vector force)
-{
-       local   entity dbr;
-
-       dbr = spawn();
-       setorigin(dbr, self.absmin
-                  + '1 0 0' * random() * (self.absmax_x - self.absmin_x)
-                  + '0 1 0' * random() * (self.absmax_y - self.absmin_y)
-                  + '0 0 1' * random() * (self.absmax_z - self.absmin_z));
-       setmodel (dbr, debrisname );
-       dbr.skin = self.debrisskin;
-       dbr.colormap = self.colormap; // inherit team colors
-       dbr.owner = self; // do not be affected by our own explosion
-       dbr.movetype = self.debrismovetype;
-       dbr.solid = self.debrissolid;
-       if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
-               setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
-       dbr.velocity_x = self.debrisvelocity_x + self.debrisvelocityjitter_x * crandom();
-       dbr.velocity_y = self.debrisvelocity_y + self.debrisvelocityjitter_y * crandom();
-       dbr.velocity_z = self.debrisvelocity_z + self.debrisvelocityjitter_z * crandom();
-       self.velocity = self.velocity + force * self.debrisdamageforcescale;
-       dbr.avelocity_x = random()*self.debrisavelocityjitter_x;
-       dbr.avelocity_y = random()*self.debrisavelocityjitter_y;
-       dbr.avelocity_z = random()*self.debrisavelocityjitter_z;
-       dbr.damageforcescale = self.debrisdamageforcescale;
-       if(dbr.damageforcescale)
-               dbr.takedamage = DAMAGE_YES;
-       SUB_SetFade(dbr, time + self.debristime + crandom() * self.debristimejitter, self.debrisfadetime);
-}
-
-void func_breakable_colormod()
-{
-       float h;
-       if (!(self.spawnflags & 2))
-               return;
-       h = self.health / self.max_health;
-       if(h < 0.25)
-               self.colormod = '1 0 0';
-       else if(h <= 0.75)
-               self.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
-       else
-               self.colormod = '1 1 1';
-               
-       CSQCMODEL_AUTOUPDATE();
-}
-
-void func_breakable_look_destroyed()
-{
-       float floor_z;
-
-       if(self.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
-               self.dropped_origin = self.origin;
-
-       if(self.mdl_dead == "")
-               self.model = "";
-       else {
-               if (self.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..
-                       floor_z = self.absmin_z;
-                       setorigin(self,((self.absmax+self.absmin)*.5));
-                       self.origin_z = floor_z;
-               }
-               setmodel(self, self.mdl_dead);
-       }
-
-       self.solid = SOLID_NOT;
-}
-
-void func_breakable_look_restore()
-{
-       setmodel(self, self.mdl);
-       if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
-               setorigin(self, self.dropped_origin);
-       self.solid = SOLID_BSP;
-}
-
-void func_breakable_behave_destroyed()
-{
-       self.health = self.max_health;
-       self.takedamage = DAMAGE_NO;
-       self.bot_attack = FALSE;
-       self.event_damage = func_null;
-       self.state = 1;
-       func_breakable_colormod();
-}
-
-void func_breakable_behave_restore()
-{
-       self.health = self.max_health;
-       if(self.sprite)
-       {
-               WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
-               WaypointSprite_UpdateHealth(self.sprite, self.health);
-       }
-       self.takedamage = DAMAGE_AIM;
-       self.bot_attack = TRUE;
-       self.event_damage = func_breakable_damage;
-       self.state = 0;
-       self.nextthink = 0; // cancel auto respawn
-       func_breakable_colormod();
-}
-
-void func_breakable_destroyed()
-{
-       func_breakable_look_destroyed();
-       func_breakable_behave_destroyed();
-       
-       CSQCMODEL_AUTOUPDATE();
-}
-
-void func_breakable_restore()
-{
-       func_breakable_look_restore();
-       func_breakable_behave_restore();
-       
-       CSQCMODEL_AUTOUPDATE();
-}
-
-vector debrisforce; // global, set before calling this
-void func_breakable_destroy() {
-       float n, i;
-       string oldmsg;
-
-       activator = self.owner;
-       self.owner = world; // set by W_PrepareExplosionByDamage
-
-       // now throw around the debris
-       n = tokenize_console(self.debris);
-       for(i = 0; i < n; ++i)
-               LaunchDebris(argv(i), debrisforce);
-
-       func_breakable_destroyed();
-
-       if(self.noise)
-               sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
-
-       if(self.dmg)
-               RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER, world);
-
-       if(self.cnt)
-               pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
-
-       if(self.respawntime)
-       {
-               self.think = func_breakable_restore;
-               self.nextthink = time + self.respawntime + crandom() * self.respawntimejitter;
-       }
-
-       oldmsg = self.message;
-       self.message = "";
-       SUB_UseTargets();
-       self.message = oldmsg;
-}
-
-void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-{
-       if(self.state == 1)
-               return;
-       if(self.spawnflags & DOOR_NOSPLASH)
-               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
-                       return;
-       if(self.team)
-               if(attacker.team == self.team)
-                       return;
-       self.health = self.health - damage;
-       if(self.sprite)
-       {
-               WaypointSprite_Ping(self.sprite);
-               WaypointSprite_UpdateHealth(self.sprite, self.health);
-       }
-       func_breakable_colormod();
-
-       if(self.health <= 0)
-       {
-               debrisforce = force;
-               W_PrepareExplosionByDamage(attacker, func_breakable_destroy);
-       }
-}
-
-void func_breakable_reset()
-{
-       self.team = self.team_saved;
-       func_breakable_look_restore();
-       if(self.spawnflags & 1)
-               func_breakable_behave_destroyed();
-       else
-               func_breakable_behave_restore();
-               
-       CSQCMODEL_AUTOUPDATE();
-}
-
-// destructible walls that can be used to trigger target_objective_decrease
-void spawnfunc_func_breakable() {
-       float n, i;
-       if(!self.health)
-               self.health = 100;
-       self.max_health = self.health;
-
-       // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
-       if(!self.debrismovetype) self.debrismovetype = MOVETYPE_BOUNCE;
-       if(!self.debrissolid) self.debrissolid = SOLID_NOT;
-       if(self.debrisvelocity == '0 0 0') self.debrisvelocity = '0 0 140';
-       if(self.debrisvelocityjitter == '0 0 0') self.debrisvelocityjitter = '70 70 70';
-       if(self.debrisavelocityjitter == '0 0 0') self.debrisavelocityjitter = '600 600 600';
-       if(!self.debristime) self.debristime = 3.5;
-       if(!self.debristimejitter) self.debristime = 2.5;
-
-       if(self.mdl != "")
-               self.cnt = particleeffectnum(self.mdl);
-       if(self.count == 0)
-               self.count = 1;
-
-       if(self.message == "")
-               self.message = "got too close to an explosion";
-       if(self.message2 == "")
-               self.message2 = "was pushed into an explosion by";
-       if(!self.dmg_radius)
-               self.dmg_radius = 150;
-       if(!self.dmg_force)
-               self.dmg_force = 200;
-
-       self.mdl = self.model;
-       SetBrushEntityModel();
-
-       self.use = func_breakable_restore;
-
-       // precache all the models
-       if (self.mdl_dead)
-               precache_model(self.mdl_dead);
-       n = tokenize_console(self.debris);
-       for(i = 0; i < n; ++i)
-               precache_model(argv(i));
-       if(self.noise)
-               precache_sound(self.noise);
-
-       self.team_saved = self.team;
-       self.dropped_origin = self.origin;
-
-       self.reset = func_breakable_reset;
-       func_breakable_reset();
-       
-       CSQCMODEL_AUTOINIT();
-}
-
-// for use in maps with a "model" key set
-void spawnfunc_misc_breakablemodel() {
-       spawnfunc_func_breakable();
-}
index 5aa07a33d986d4241cd7fe0fe35465329dfcf6c0..8da8a6fc55185d1f58773abfc2e89b70107f76be 100644 (file)
@@ -104,7 +104,6 @@ round_handler.qh
 
 // singleplayer stuff
 item_key.qh
-secret.qh
 
 scores_rules.qc
 
@@ -150,7 +149,6 @@ g_models.qc
 
 // singleplayer stuff
 item_key.qc
-secret.qc
 
 weapons/accuracy.qc
 weapons/common.qc
@@ -221,10 +219,6 @@ spawnpoints.qc
 
 portals.qc
 
-target_spawn.qc
-func_breakable.qc
-target_music.qc
-
 ../common/nades.qc
 ../common/buffs.qc
 
diff --git a/qcsrc/server/secret.qc b/qcsrc/server/secret.qc
deleted file mode 100644 (file)
index 06f7e07..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-void secrets_setstatus() {
-       self.stat_secrets_total = secrets_total;
-       self.stat_secrets_found = secrets_found;
-}
-
-/**
- * A secret has been found (maybe :P)
- */
-void trigger_secret_touch() {
-       // only a player can trigger this
-       if (!IS_PLAYER(other))
-               return;
-
-       // update secrets found counter
-       secrets_found += 1;
-       //print("Secret found: ", ftos(secret_counter.cnt), "/");
-       //print(ftos(secret_counter.count), "\n");
-
-       // centerprint message (multi_touch() doesn't always call centerprint())
-       centerprint(other, self.message);
-       self.message = "";
-
-       // handle normal trigger features
-       multi_touch();
-       remove(self);
-}
-
-/*QUAKED trigger_secret (.5 .5 .5) ?
-Variable sized secret trigger. Can be targeted at one or more entities.
-Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
--------- KEYS --------
-sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
-noise: path to sound file, if you want to play something else
-target: trigger all entities with this targetname when triggered
-message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
-killtarget: remove all entities with this targetname when triggered
--------- NOTES --------
-You should create a common/trigger textured brush covering the entrance to a secret room/area.
-Trigger secret can only be trigger by a player's touch and can not be a target itself.
-*/
-void spawnfunc_trigger_secret() {
-       // FIXME: should it be disabled in most modes?
-
-       // update secrets count
-       secrets_total += 1;
-
-       // add default message
-       if (self.message == "")
-               self.message = "You found a secret!";
-
-       // set default sound
-       if (self.noise == "")
-       if (!self.sounds)
-               self.sounds = 1; // misc/secret.wav
-
-       // this entity can't be a target itself!!!!
-       self.targetname = "";
-
-       // you can't just shoot a room to find it, can you?
-       self.health = 0;
-
-       // a secret can not be delayed
-       self.delay = 0;
-
-       // convert this trigger to trigger_once
-       self.classname = "trigger_once";
-       spawnfunc_trigger_once();
-
-       // take over the touch() function, so we can mark secret as found
-       self.touch = trigger_secret_touch;
-       // ignore triggering;
-       self.use = func_null;
-}
-
diff --git a/qcsrc/server/secret.qh b/qcsrc/server/secret.qh
deleted file mode 100644 (file)
index dd94b19..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Total number of secrets on the map.
- */
-float secrets_total;
-
-/**
- * Total numbe of secrets found on the map.
- */
-float secrets_found;
-
-
-.float stat_secrets_total;
-.float stat_secrets_found;
-
-/**
- * update secrets status.
- */
-void secrets_setstatus();
-
diff --git a/qcsrc/server/target_music.qc b/qcsrc/server/target_music.qc
deleted file mode 100644 (file)
index cd1b374..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-.float lifetime;
-// values:
-//   volume
-//   noise
-//   targetname
-//   lifetime
-//   fade_time
-//   fade_rate
-// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
-// when targetname is not set, THIS ONE is default
-void target_music_sendto(float to, float is)
-{
-       WriteByte(to, SVC_TEMPENTITY);
-       WriteByte(to, TE_CSQC_TARGET_MUSIC);
-       WriteShort(to, num_for_edict(self));
-       WriteByte(to, self.volume * 255.0 * is);
-       WriteByte(to, self.fade_time * 16.0);
-       WriteByte(to, self.fade_rate * 16.0);
-       WriteByte(to, self.lifetime);
-       WriteString(to, self.noise);
-}
-void target_music_reset()
-{
-       if(self.targetname == "")
-               target_music_sendto(MSG_ALL, 1);
-}
-void target_music_use()
-{
-       if(!activator)
-               return;
-       if(IS_REAL_CLIENT(activator))
-       {
-               msg_entity = activator;
-               target_music_sendto(MSG_ONE, 1);
-       }
-       entity head;
-       FOR_EACH_SPEC(head) if(head.enemy == activator) { msg_entity = head; target_music_sendto(MSG_ONE, 1); }
-}
-void spawnfunc_target_music()
-{
-       self.use = target_music_use;
-       self.reset = target_music_reset;
-       if(!self.volume)
-               self.volume = 1;
-       if(self.targetname == "")
-               target_music_sendto(MSG_INIT, 1);
-       else
-               target_music_sendto(MSG_INIT, 0);
-}
-void TargetMusic_RestoreGame()
-{
-       for(self = world; (self = find(self, classname, "target_music")); )
-       {
-               if(self.targetname == "")
-                       target_music_sendto(MSG_INIT, 1);
-               else
-                       target_music_sendto(MSG_INIT, 0);
-       }
-}
-// values:
-//   volume
-//   noise
-//   targetname
-//   fade_time
-// spawnflags:
-//   1 = START_OFF
-// when triggered, it is disabled/enabled for everyone
-float trigger_music_SendEntity(entity to, float sf)
-{
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
-       sf &= ~0x80;
-       if(self.cnt)
-               sf |= 0x80;
-       WriteByte(MSG_ENTITY, sf);
-       if(sf & 4)
-       {
-               WriteCoord(MSG_ENTITY, self.origin_x);
-               WriteCoord(MSG_ENTITY, self.origin_y);
-               WriteCoord(MSG_ENTITY, self.origin_z);
-       }
-       if(sf & 1)
-       {
-               if(self.model != "null")
-               {
-                       WriteShort(MSG_ENTITY, self.modelindex);
-                       WriteCoord(MSG_ENTITY, self.mins_x);
-                       WriteCoord(MSG_ENTITY, self.mins_y);
-                       WriteCoord(MSG_ENTITY, self.mins_z);
-                       WriteCoord(MSG_ENTITY, self.maxs_x);
-                       WriteCoord(MSG_ENTITY, self.maxs_y);
-                       WriteCoord(MSG_ENTITY, self.maxs_z);
-               }
-               else
-               {
-                       WriteShort(MSG_ENTITY, 0);
-                       WriteCoord(MSG_ENTITY, self.maxs_x);
-                       WriteCoord(MSG_ENTITY, self.maxs_y);
-                       WriteCoord(MSG_ENTITY, self.maxs_z);
-               }
-               WriteByte(MSG_ENTITY, self.volume * 255.0);
-               WriteByte(MSG_ENTITY, self.fade_time * 16.0);
-               WriteByte(MSG_ENTITY, self.fade_rate * 16.0);
-               WriteString(MSG_ENTITY, self.noise);
-       }
-       return 1;
-}
-void trigger_music_reset()
-{
-       self.cnt = !(self.spawnflags & 1);
-       self.SendFlags |= 0x80;
-}
-void trigger_music_use()
-{
-       self.cnt = !self.cnt;
-       self.SendFlags |= 0x80;
-}
-void spawnfunc_trigger_music()
-{
-       if(self.model != "")
-               setmodel(self, self.model);
-       if(!self.volume)
-               self.volume = 1;
-       if(!self.modelindex)
-       {
-               setorigin(self, self.origin + self.mins);
-               setsize(self, '0 0 0', self.maxs - self.mins);
-       }
-       trigger_music_reset();
-
-       self.use = trigger_music_use;
-       self.reset = trigger_music_reset;
-
-       Net_LinkEntity(self, FALSE, 0, trigger_music_SendEntity);
-}
diff --git a/qcsrc/server/target_spawn.qc b/qcsrc/server/target_spawn.qc
deleted file mode 100644 (file)
index 4da6b13..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-// spawner entity
-// "classname" "target_spawn"
-// "message" "fieldname value fieldname value ..."
-// "spawnflags"
-//   1 = call the spawn function
-//   2 = trigger on map load
-
-float target_spawn_initialized;
-.void() target_spawn_spawnfunc;
-float target_spawn_spawnfunc_field;
-.entity target_spawn_activator;
-.float target_spawn_id;
-float target_spawn_count;
-
-void target_spawn_helper_setmodel()
-{
-       setmodel(self, self.model);
-}
-
-void target_spawn_helper_setsize()
-{
-       setsize(self, self.mins, self.maxs);
-}
-
-void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act)
-{
-       float i, n, valuefieldpos;
-       string key, value, valuefield, valueoffset, valueoffsetrandom;
-       entity valueent;
-       vector data, data2;
-       entity oldself;
-       entity oldactivator;
-
-       n = tokenize_console(msg);
-
-       for(i = 0; i < n-1; i += 2)
-       {
-               key = argv(i);
-               value = argv(i+1);
-               if(key == "$")
-               {
-                       data_x = -1;
-                       data_y = FIELD_STRING;
-               }
-               else
-               {
-                       data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
-                       if(data_y == 0) // undefined field, i.e., invalid type
-                       {
-                               print("target_spawn: invalid/unknown entity key ", key, " specified, ignored!\n");
-                               continue;
-                       }
-               }
-               if(substring(value, 0, 1) == "$")
-               {
-                       value = substring(value, 1, strlen(value) - 1);
-                       if(substring(value, 0, 1) == "$")
-                       {
-                               // deferred replacement
-                               // do nothing
-                               // useful for creating target_spawns with this!
-                       }
-                       else
-                       {
-                               // replace me!
-                               valuefieldpos = strstrofs(value, "+", 0);
-                               valueoffset = "";
-                               if(valuefieldpos != -1)
-                               {
-                                       valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
-                                       value = substring(value, 0, valuefieldpos);
-                               }
-
-                               valuefieldpos = strstrofs(valueoffset, "+", 0);
-                               valueoffsetrandom = "";
-                               if(valuefieldpos != -1)
-                               {
-                                       valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
-                                       valueoffset = substring(valueoffset, 0, valuefieldpos);
-                               }
-
-                               valuefieldpos = strstrofs(value, ".", 0);
-                               valuefield = "";
-                               if(valuefieldpos != -1)
-                               {
-                                       valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
-                                       value = substring(value, 0, valuefieldpos);
-                               }
-
-                               if(value == "self")
-                               {
-                                       valueent = self;
-                                       value = "";
-                               }
-                               else if(value == "activator")
-                               {
-                                       valueent = act;
-                                       value = "";
-                               }
-                               else if(value == "other")
-                               {
-                                       valueent = other;
-                                       value = "";
-                               }
-                               else if(value == "pusher")
-                               {
-                                       if(time < act.pushltime)
-                                               valueent = act.pusher;
-                                       else
-                                               valueent = world;
-                                       value = "";
-                               }
-                               else if(value == "target")
-                               {
-                                       valueent = e;
-                                       value = "";
-                               }
-                               else if(value == "killtarget")
-                               {
-                                       valueent = kt;
-                                       value = "";
-                               }
-                               else if(value == "target2")
-                               {
-                                       valueent = t2;
-                                       value = "";
-                               }
-                               else if(value == "target3")
-                               {
-                                       valueent = t3;
-                                       value = "";
-                               }
-                               else if(value == "target4")
-                               {
-                                       valueent = t4;
-                                       value = "";
-                               }
-                               else if(value == "time")
-                               {
-                                       valueent = world;
-                                       value = ftos(time);
-                               }
-                               else
-                               {
-                                       print("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!\n");
-                                       continue;
-                               }
-
-                               if(valuefield == "")
-                               {
-                                       if(value == "")
-                                               value = ftos(num_for_edict(valueent));
-                               }
-                               else
-                               {
-                                       if(value != "")
-                                       {
-                                               print("target_spawn: try to get a field of a non-entity, ignored!\n");
-                                               continue;
-                                       }
-                                       data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
-                                       if(data2_y == 0) // undefined field, i.e., invalid type
-                                       {
-                                               print("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!\n");
-                                               continue;
-                                       }
-                                       value = getentityfieldstring(data2_x, valueent);
-                               }
-
-                               if(valueoffset != "")
-                               {
-                                       switch(data_y)
-                                       {
-                                               case FIELD_STRING:
-                                                       value = strcat(value, valueoffset);
-                                                       break;
-                                               case FIELD_FLOAT:
-                                                       value = ftos(stof(value) + stof(valueoffset));
-                                                       break;
-                                               case FIELD_VECTOR:
-                                                       value = vtos(stov(value) + stov(valueoffset));
-                                                       break;
-                                               default:
-                                                       print("target_spawn: only string, float and vector fields can do calculations, calculation ignored!\n");
-                                                       break;
-                                       }
-                               }
-
-                               if(valueoffsetrandom != "")
-                               {
-                                       switch(data_y)
-                                       {
-                                               case FIELD_FLOAT:
-                                                       value = ftos(stof(value) + random() * stof(valueoffsetrandom));
-                                                       break;
-                                               case FIELD_VECTOR:
-                                                       data2 = stov(valueoffsetrandom);
-                                                       value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
-                                                       break;
-                                               default:
-                                                       print("target_spawn: only float and vector fields can do random calculations, calculation ignored!\n");
-                                                       break;
-                                       }
-                               }
-                       }
-               }
-               if(key == "$")
-               {
-                       if(substring(value, 0, 1) == "_")
-                               value = strcat("target_spawn_helper", value);
-                       putentityfieldstring(target_spawn_spawnfunc_field, e, value);
-
-                       oldself = self;
-                       oldactivator = activator;
-
-                       self = e;
-                       activator = act;
-
-                       self.target_spawn_spawnfunc();
-
-                       self = oldself;
-                       activator = oldactivator;
-               }
-               else
-               {
-                       if(data_y == FIELD_VECTOR)
-                               value = strreplace("'", "", value); // why?!?
-                       putentityfieldstring(data_x, e, value);
-               }
-       }
-}
-
-void target_spawn_useon(entity e)
-{
-       self.target_spawn_activator = activator;
-       target_spawn_edit_entity(
-               e,
-               self.message,
-               find(world, targetname, self.killtarget),
-               find(world, targetname, self.target2),
-               find(world, targetname, self.target3),
-               find(world, targetname, self.target4),
-               activator
-       );
-}
-
-float target_spawn_cancreate()
-{
-       float c;
-       entity e;
-
-       c = self.count;
-       if(c == 0) // no limit?
-               return 1;
-
-       ++c; // increase count to not include MYSELF
-       for(e = world; (e = findfloat(e, target_spawn_id, self.target_spawn_id)); --c)
-               ;
-
-       // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
-       if(c == 0)
-               return 0;
-       return 1;
-}
-
-void target_spawn_use()
-{
-       entity e;
-
-       if(self.target == "")
-       {
-               // spawn new entity
-               if(!target_spawn_cancreate())
-                       return;
-               e = spawn();
-               target_spawn_useon(e);
-               e.target_spawn_id = self.target_spawn_id;
-       }
-       else if(self.target == "*activator")
-       {
-               // edit entity
-               if(activator)
-                       target_spawn_useon(activator);
-       }
-       else
-       {
-               // edit entity
-               for(e = world; (e = find(e, targetname, self.target)); )
-                       target_spawn_useon(e);
-       }
-}
-
-void target_spawn_spawnfirst()
-{
-       activator = self.target_spawn_activator;
-       if(self.spawnflags & 2)
-               target_spawn_use();
-}
-
-void initialize_field_db()
-{
-       if(!target_spawn_initialized)
-       {
-               float n, i;
-               string fn;
-               vector prev, new;
-               float ft;
-
-               n = numentityfields();
-               for(i = 0; i < n; ++i)
-               {
-                       fn = entityfieldname(i);
-                       ft = entityfieldtype(i);
-                       new = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
-                       prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
-                       if(prev_y == 0)
-                       {
-                               db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(new));
-                               if(fn == "target_spawn_spawnfunc")
-                                       target_spawn_spawnfunc_field = i;
-                       }
-               }
-
-               target_spawn_initialized = 1;
-       }
-}
-
-void spawnfunc_target_spawn()
-{
-       initialize_field_db();
-       self.use = target_spawn_use;
-       self.message = strzone(strreplace("'", "\"", self.message));
-       self.target_spawn_id = ++target_spawn_count;
-       InitializeEntity(self, target_spawn_spawnfirst, INITPRIO_LAST);
-}
-
-
-void trigger_relay_if_use()
-{
-       float n;
-       n = self.count;
-
-       // TODO make this generic AND faster than nextent()ing through all, if somehow possible
-       n = (cvar_string(self.netname) == cvar_string(self.message));
-       if(self.spawnflags & 1)
-               n = !n;
-
-       if(n)
-               SUB_UseTargets();
-}
-
-void spawnfunc_trigger_relay_if()
-{
-       self.use = trigger_relay_if_use;
-}
index 521cf343b3efa6b32dae20181218cce6a3224104..16e026d4861a3726b7aa47edfdcb0b3d6b8f3887 100644 (file)
@@ -564,6 +564,45 @@ vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
        return nearest;
 }
 
+float WarpZoneLib_BadClassname(string myclassname)
+{
+       switch(myclassname)
+       {
+               case "weapon_info":
+               case "monster_info":
+               case "deathtype":
+               case "callback":
+               case "callbackchain":
+               case "weaponentity":
+               case "exteriorweaponentity":
+               case "csqc_score_team":
+               case "pingplreport":
+               case "ent_client_scoreinfo":
+               case "saved_cvar_value":
+               case "accuracy":
+               case "entcs_sender_v2":
+               case "entcs_receiver_v2":
+               case "clientinit":
+               case "sprite_waypoint":
+               case "waypoint":
+               case "gibsplash":
+               //case "net_linked": // actually some real entities are linked without classname, fail
+               case "":
+                       return TRUE;
+       }
+
+       if(startsWith(myclassname, "msg_"))
+               return TRUE;
+
+       if(startsWith(myclassname, "target_"))
+               return TRUE;
+
+       if(startsWith(myclassname, "info_"))
+               return TRUE;
+
+       return FALSE;
+}
+
 .float WarpZone_findradius_hit;
 .entity WarpZone_findradius_next;
 void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,               vector transform, vector shift, float needlineofsight)
@@ -582,6 +621,9 @@ void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,
 
        for(e = e0; e; e = e.chain)
        {
+               if(WarpZoneLib_BadClassname(e.classname))
+                       continue;
+               print(e.classname, ", first check\n");
                p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
                if(needlineofsight)
                {
@@ -617,6 +659,11 @@ void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,
        }
        for(e = wz; e; e = e.WarpZone_findradius_next)
        {
+               if(WarpZoneLib_BadClassname(e.classname))
+                       continue;
+
+               print(e.classname, ", second check\n");
+
                org0_new = WarpZone_TransformOrigin(e, org);
                traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
                org_new = trace_endpos;