aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/game/GameTarget.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jake2/game/GameTarget.java')
-rw-r--r--src/jake2/game/GameTarget.java1104
1 files changed, 852 insertions, 252 deletions
diff --git a/src/jake2/game/GameTarget.java b/src/jake2/game/GameTarget.java
index 8a13ade..b612168 100644
--- a/src/jake2/game/GameTarget.java
+++ b/src/jake2/game/GameTarget.java
@@ -1,260 +1,860 @@
/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
+ * Copyright (C) 1997-2001 Id Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
// Created on 28.12.2003 by RST.
-// $Id: GameTarget.java,v 1.2 2004-07-08 15:58:43 hzi Exp $
-
+// $Id: GameTarget.java,v 1.3 2004-09-22 19:22:03 salomo Exp $
package jake2.game;
-import jake2.*;
-import jake2.client.*;
-import jake2.qcommon.*;
-import jake2.render.*;
-import jake2.server.*;
+import jake2.Defines;
+import jake2.Globals;
import jake2.util.Lib;
import jake2.util.Math3D;
-public class GameTarget extends GameTurret {
-
- public static void SP_target_temp_entity(edict_t ent) {
- ent.use = GameTargetAdapters.Use_Target_Tent;
- }
-
- public static void SP_target_speaker(edict_t ent) {
- //char buffer[MAX_QPATH];
- String buffer;
-
- if (st.noise == null) {
- gi.dprintf("target_speaker with no noise set at " + vtos(ent.s.origin) + "\n");
- return;
- }
- if (st.noise.indexOf(".wav") < 0)
- buffer = "" + st.noise + ".wav";
- //Com_sprintf(buffer, sizeof(buffer), "%s.wav", st.noise);
- else
- //strncpy(buffer, st.noise, sizeof(buffer));
- buffer = st.noise;
-
- ent.noise_index = gi.soundindex(buffer);
-
- if (ent.volume == 0)
- ent.volume = 1.0f;
-
- if (ent.attenuation == 0)
- ent.attenuation = 1.0f;
- else if (ent.attenuation == -1) // use -1 so 0 defaults to 1
- ent.attenuation = 0;
-
- // check for prestarted looping sound
- if ((ent.spawnflags & 1) != 0)
- ent.s.sound = ent.noise_index;
-
- ent.use = GameTargetAdapters.Use_Target_Speaker;
-
- // must link the entity so we get areas and clusters so
- // the server can determine who to send updates to
- gi.linkentity(ent);
- }
-
- /*QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1
- When fired, the "message" key becomes the current personal computer string, and the message light will be set on all clients status bars.
- */
- public static void SP_target_help(edict_t ent) {
- if (deathmatch.value != 0) { // auto-remove for deathmatch
- G_FreeEdict(ent);
- return;
- }
-
- if (ent.message == null) {
- gi.dprintf(ent.classname + " with no message at " + vtos(ent.s.origin) + "\n");
- G_FreeEdict(ent);
- return;
- }
- ent.use = GameTargetAdapters.Use_Target_Help;
- }
-
- public static void SP_target_secret(edict_t ent) {
- if (deathmatch.value != 0) { // auto-remove for deathmatch
- G_FreeEdict(ent);
- return;
- }
-
- ent.use = GameTargetAdapters.use_target_secret;
- if (st.noise == null)
- st.noise = "misc/secret.wav";
- ent.noise_index = gi.soundindex(st.noise);
- ent.svflags = SVF_NOCLIENT;
- level.total_secrets++;
- // map bug hack
- if (0 == Q_stricmp(level.mapname, "mine3") && ent.s.origin[0] == 280 && ent.s.origin[1] == -2048 && ent.s.origin[2] == -624)
- ent.message = "You have found a secret area.";
- }
-
- public static void SP_target_goal(edict_t ent) {
- if (deathmatch.value != 0) { // auto-remove for deathmatch
- G_FreeEdict(ent);
- return;
- }
-
- ent.use = GameTargetAdapters.use_target_goal;
- if (st.noise == null)
- st.noise = "misc/secret.wav";
- ent.noise_index = gi.soundindex(st.noise);
- ent.svflags = SVF_NOCLIENT;
- level.total_goals++;
- }
-
- public static void SP_target_explosion(edict_t ent) {
- ent.use = GameTargetAdapters.use_target_explosion;
- ent.svflags = SVF_NOCLIENT;
- }
-
- public static void SP_target_changelevel(edict_t ent) {
- if (ent.map == null) {
- gi.dprintf("target_changelevel with no map at " + vtos(ent.s.origin) + "\n");
- G_FreeEdict(ent);
- return;
- }
-
- // ugly hack because *SOMEBODY* screwed up their map
- if ((Q_stricmp(level.mapname, "fact1") == 0) && (Q_stricmp(ent.map, "fact3") == 0))
- ent.map = "fact3$secret1";
-
- ent.use = GameTargetAdapters.use_target_changelevel;
- ent.svflags = SVF_NOCLIENT;
- }
-
- public static void SP_target_splash(edict_t self) {
- self.use = GameTargetAdapters.use_target_splash;
- G_SetMovedir(self.s.angles, self.movedir);
-
- if (0 == self.count)
- self.count = 32;
-
- self.svflags = SVF_NOCLIENT;
- }
-
- public static void SP_target_spawner(edict_t self) {
- self.use = GameTargetAdapters.use_target_spawner;
- self.svflags = SVF_NOCLIENT;
- if (self.speed != 0) {
- G_SetMovedir(self.s.angles, self.movedir);
- VectorScale(self.movedir, self.speed, self.movedir);
- }
- }
-
- public static void SP_target_blaster(edict_t self) {
- self.use = GameTargetAdapters.use_target_blaster;
- G_SetMovedir(self.s.angles, self.movedir);
- self.noise_index = gi.soundindex("weapons/laser2.wav");
-
- if (0 == self.dmg)
- self.dmg = 15;
- if (0 == self.speed)
- self.speed = 1000;
-
- self.svflags = SVF_NOCLIENT;
- }
-
- public static void SP_target_crosslevel_trigger(edict_t self) {
- self.svflags = SVF_NOCLIENT;
- self.use = GameTargetAdapters.trigger_crosslevel_trigger_use;
- }
-
- public static void SP_target_crosslevel_target(edict_t self) {
- if (0 == self.delay)
- self.delay = 1;
- self.svflags = SVF_NOCLIENT;
-
- self.think = GameTargetAdapters.target_crosslevel_target_think;
- self.nextthink = level.time + self.delay;
- }
-
- public static void target_laser_on(edict_t self) {
- if (null == self.activator)
- self.activator = self;
- self.spawnflags |= 0x80000001;
- self.svflags &= ~SVF_NOCLIENT;
- GameTargetAdapters.target_laser_think.think(self);
- }
-
- public static void target_laser_off(edict_t self) {
- self.spawnflags &= ~1;
- self.svflags |= SVF_NOCLIENT;
- self.nextthink = 0;
- }
-
- public static void SP_target_laser(edict_t self) {
- // let everything else get spawned before we start firing
- self.think = GameTargetAdapters.target_laser_start;
- self.nextthink = level.time + 1;
- }
-
- public static void SP_target_lightramp(edict_t self) {
- if (self.message == null
- || self.message.length() != 2
- || self.message.charAt(0) < 'a'
- || self.message.charAt(0) > 'z'
- || self.message.charAt(1) < 'a'
- || self.message.charAt(1) > 'z'
- || self.message.charAt(0) == self.message.charAt(1)) {
- gi.dprintf("target_lightramp has bad ramp (" + self.message + ") at " + vtos(self.s.origin) + "\n");
- G_FreeEdict(self);
- return;
- }
-
- if (deathmatch.value != 9) {
- G_FreeEdict(self);
- return;
- }
-
- if (self.target == null) {
- gi.dprintf(self.classname + " with no target at " + vtos(self.s.origin) + "\n");
- G_FreeEdict(self);
- return;
- }
-
- self.svflags |= SVF_NOCLIENT;
- self.use = GameTargetAdapters.target_lightramp_use;
- self.think = GameTargetAdapters.target_lightramp_think;
-
- self.movedir[0] = self.message.charAt(0) - 'a';
- self.movedir[1] = self.message.charAt(1) - 'a';
- self.movedir[2] = (self.movedir[1] - self.movedir[0]) / (self.speed / FRAMETIME);
- }
-
- public static void SP_target_earthquake(edict_t self) {
- if (null == self.targetname)
- gi.dprintf("untargeted " + self.classname + " at " + vtos(self.s.origin) + "\n");
-
- if (0 == self.count)
- self.count = 5;
-
- if (0 == self.speed)
- self.speed = 200;
-
- self.svflags |= SVF_NOCLIENT;
- self.think = GameTargetAdapters.target_earthquake_think;
- self.use = GameTargetAdapters.target_earthquake_use;
-
- self.noise_index = gi.soundindex("world/quake.wav");
- }
-
-}
+public class GameTarget {
+
+ public static void SP_target_temp_entity(edict_t ent) {
+ ent.use = GameTarget.Use_Target_Tent;
+ }
+
+ public static void SP_target_speaker(edict_t ent) {
+ //char buffer[MAX_QPATH];
+ String buffer;
+
+ if (GameBase.st.noise == null) {
+ GameBase.gi.dprintf("target_speaker with no noise set at "
+ + Lib.vtos(ent.s.origin) + "\n");
+ return;
+ }
+ if (GameBase.st.noise.indexOf(".wav") < 0)
+ buffer = "" + GameBase.st.noise + ".wav";
+ //Com_sprintf(buffer, sizeof(buffer), "%s.wav", st.noise);
+ else
+ //strncpy(buffer, st.noise, sizeof(buffer));
+ buffer = GameBase.st.noise;
+
+ ent.noise_index = GameBase.gi.soundindex(buffer);
+
+ if (ent.volume == 0)
+ ent.volume = 1.0f;
+
+ if (ent.attenuation == 0)
+ ent.attenuation = 1.0f;
+ else if (ent.attenuation == -1) // use -1 so 0 defaults to 1
+ ent.attenuation = 0;
+
+ // check for prestarted looping sound
+ if ((ent.spawnflags & 1) != 0)
+ ent.s.sound = ent.noise_index;
+
+ ent.use = GameTarget.Use_Target_Speaker;
+
+ // must link the entity so we get areas and clusters so
+ // the server can determine who to send updates to
+ GameBase.gi.linkentity(ent);
+ }
+
+ /*
+ * QUAKED target_help (1 0 1) (-16 -16 -24) (16 16 24) help1 When fired, the
+ * "message" key becomes the current personal computer string, and the
+ * message light will be set on all clients status bars.
+ */
+ public static void SP_target_help(edict_t ent) {
+ if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch
+ GameUtil.G_FreeEdict(ent);
+ return;
+ }
+
+ if (ent.message == null) {
+ GameBase.gi.dprintf(ent.classname + " with no message at "
+ + Lib.vtos(ent.s.origin) + "\n");
+ GameUtil.G_FreeEdict(ent);
+ return;
+ }
+ ent.use = GameTarget.Use_Target_Help;
+ }
+
+ public static void SP_target_secret(edict_t ent) {
+ if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch
+ GameUtil.G_FreeEdict(ent);
+ return;
+ }
+
+ ent.use = GameTarget.use_target_secret;
+ if (GameBase.st.noise == null)
+ GameBase.st.noise = "misc/secret.wav";
+ ent.noise_index = GameBase.gi.soundindex(GameBase.st.noise);
+ ent.svflags = Defines.SVF_NOCLIENT;
+ GameBase.level.total_secrets++;
+ // map bug hack
+ if (0 == Lib.Q_stricmp(GameBase.level.mapname, "mine3")
+ && ent.s.origin[0] == 280 && ent.s.origin[1] == -2048
+ && ent.s.origin[2] == -624)
+ ent.message = "You have found a secret area.";
+ }
+
+ public static void SP_target_goal(edict_t ent) {
+ if (GameBase.deathmatch.value != 0) { // auto-remove for deathmatch
+ GameUtil.G_FreeEdict(ent);
+ return;
+ }
+
+ ent.use = GameTarget.use_target_goal;
+ if (GameBase.st.noise == null)
+ GameBase.st.noise = "misc/secret.wav";
+ ent.noise_index = GameBase.gi.soundindex(GameBase.st.noise);
+ ent.svflags = Defines.SVF_NOCLIENT;
+ GameBase.level.total_goals++;
+ }
+
+ public static void SP_target_explosion(edict_t ent) {
+ ent.use = GameTarget.use_target_explosion;
+ ent.svflags = Defines.SVF_NOCLIENT;
+ }
+
+ public static void SP_target_changelevel(edict_t ent) {
+ if (ent.map == null) {
+ GameBase.gi.dprintf("target_changelevel with no map at "
+ + Lib.vtos(ent.s.origin) + "\n");
+ GameUtil.G_FreeEdict(ent);
+ return;
+ }
+
+ // ugly hack because *SOMEBODY* screwed up their map
+ if ((Lib.Q_stricmp(GameBase.level.mapname, "fact1") == 0)
+ && (Lib.Q_stricmp(ent.map, "fact3") == 0))
+ ent.map = "fact3$secret1";
+
+ ent.use = GameTarget.use_target_changelevel;
+ ent.svflags = Defines.SVF_NOCLIENT;
+ }
+
+ public static void SP_target_splash(edict_t self) {
+ self.use = GameTarget.use_target_splash;
+ GameBase.G_SetMovedir(self.s.angles, self.movedir);
+
+ if (0 == self.count)
+ self.count = 32;
+
+ self.svflags = Defines.SVF_NOCLIENT;
+ }
+
+ public static void SP_target_spawner(edict_t self) {
+ self.use = GameTarget.use_target_spawner;
+ self.svflags = Defines.SVF_NOCLIENT;
+ if (self.speed != 0) {
+ GameBase.G_SetMovedir(self.s.angles, self.movedir);
+ Math3D.VectorScale(self.movedir, self.speed, self.movedir);
+ }
+ }
+
+ public static void SP_target_blaster(edict_t self) {
+ self.use = GameTarget.use_target_blaster;
+ GameBase.G_SetMovedir(self.s.angles, self.movedir);
+ self.noise_index = GameBase.gi.soundindex("weapons/laser2.wav");
+
+ if (0 == self.dmg)
+ self.dmg = 15;
+ if (0 == self.speed)
+ self.speed = 1000;
+
+ self.svflags = Defines.SVF_NOCLIENT;
+ }
+
+ public static void SP_target_crosslevel_trigger(edict_t self) {
+ self.svflags = Defines.SVF_NOCLIENT;
+ self.use = GameTarget.trigger_crosslevel_trigger_use;
+ }
+
+ public static void SP_target_crosslevel_target(edict_t self) {
+ if (0 == self.delay)
+ self.delay = 1;
+ self.svflags = Defines.SVF_NOCLIENT;
+
+ self.think = GameTarget.target_crosslevel_target_think;
+ self.nextthink = GameBase.level.time + self.delay;
+ }
+
+ public static void target_laser_on(edict_t self) {
+ if (null == self.activator)
+ self.activator = self;
+ self.spawnflags |= 0x80000001;
+ self.svflags &= ~Defines.SVF_NOCLIENT;
+ GameTarget.target_laser_think.think(self);
+ }
+
+ public static void target_laser_off(edict_t self) {
+ self.spawnflags &= ~1;
+ self.svflags |= Defines.SVF_NOCLIENT;
+ self.nextthink = 0;
+ }
+
+ public static void SP_target_laser(edict_t self) {
+ // let everything else get spawned before we start firing
+ self.think = GameTarget.target_laser_start;
+ self.nextthink = GameBase.level.time + 1;
+ }
+
+ public static void SP_target_lightramp(edict_t self) {
+ if (self.message == null || self.message.length() != 2
+ || self.message.charAt(0) < 'a' || self.message.charAt(0) > 'z'
+ || self.message.charAt(1) < 'a' || self.message.charAt(1) > 'z'
+ || self.message.charAt(0) == self.message.charAt(1)) {
+ GameBase.gi.dprintf("target_lightramp has bad ramp ("
+ + self.message + ") at " + Lib.vtos(self.s.origin) + "\n");
+ GameUtil.G_FreeEdict(self);
+ return;
+ }
+
+ if (GameBase.deathmatch.value != 9) {
+ GameUtil.G_FreeEdict(self);
+ return;
+ }
+
+ if (self.target == null) {
+ GameBase.gi.dprintf(self.classname + " with no target at "
+ + Lib.vtos(self.s.origin) + "\n");
+ GameUtil.G_FreeEdict(self);
+ return;
+ }
+
+ self.svflags |= Defines.SVF_NOCLIENT;
+ self.use = GameTarget.target_lightramp_use;
+ self.think = GameTarget.target_lightramp_think;
+
+ self.movedir[0] = self.message.charAt(0) - 'a';
+ self.movedir[1] = self.message.charAt(1) - 'a';
+ self.movedir[2] = (self.movedir[1] - self.movedir[0])
+ / (self.speed / Defines.FRAMETIME);
+ }
+
+ public static void SP_target_earthquake(edict_t self) {
+ if (null == self.targetname)
+ GameBase.gi.dprintf("untargeted " + self.classname + " at "
+ + Lib.vtos(self.s.origin) + "\n");
+
+ if (0 == self.count)
+ self.count = 5;
+
+ if (0 == self.speed)
+ self.speed = 200;
+
+ self.svflags |= Defines.SVF_NOCLIENT;
+ self.think = GameTarget.target_earthquake_think;
+ self.use = GameTarget.target_earthquake_use;
+
+ self.noise_index = GameBase.gi.soundindex("world/quake.wav");
+ }
+
+ /*
+ * QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8) Fire an origin based
+ * temp entity event to the clients. "style" type byte
+ */
+ public static EntUseAdapter Use_Target_Tent = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(ent.style);
+ GameBase.gi.WritePosition(ent.s.origin);
+ GameBase.gi.multicast(ent.s.origin, Defines.MULTICAST_PVS);
+ }
+ };
+
+ //==========================================================
+
+ //==========================================================
+
+ /*
+ * QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off
+ * reliable "noise" wav file to play "attenuation" -1 = none, send to whole
+ * level 1 = normal fighting sounds 2 = idle sound level 3 = ambient sound
+ * level "volume" 0.0 to 1.0
+ *
+ * Normal sounds play each time the target is used. The reliable flag can be
+ * set for crucial voiceovers.
+ *
+ * Looped sounds are always atten 3 / vol 1, and the use function toggles it
+ * on/off. Multiple identical looping sounds will just increase volume
+ * without any speed cost.
+ */
+ public static EntUseAdapter Use_Target_Speaker = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ int chan;
+
+ if ((ent.spawnflags & 3) != 0) { // looping sound toggles
+ if (ent.s.sound != 0)
+ ent.s.sound = 0; // turn it off
+ else
+ ent.s.sound = ent.noise_index; // start it
+ } else { // normal sound
+ if ((ent.spawnflags & 4) != 0)
+ chan = Defines.CHAN_VOICE | Defines.CHAN_RELIABLE;
+ else
+ chan = Defines.CHAN_VOICE;
+ // use a positioned_sound, because this entity won't normally be
+ // sent to any clients because it is invisible
+ GameBase.gi.positioned_sound(ent.s.origin, ent, chan,
+ ent.noise_index, ent.volume, ent.attenuation, 0);
+ }
+
+ }
+ };
+
+ //==========================================================
+ public static EntUseAdapter Use_Target_Help = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+
+ if ((ent.spawnflags & 1) != 0)
+ GameBase.game.helpmessage1 = ent.message;
+ else
+ GameBase.game.helpmessage2 = ent.message;
+
+ GameBase.game.helpchanged++;
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_secret (1 0 1) (-8 -8 -8) (8 8 8) Counts a secret found.
+ * These are single use targets.
+ */
+ static EntUseAdapter use_target_secret = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1,
+ Defines.ATTN_NORM, 0);
+
+ GameBase.level.found_secrets++;
+
+ GameUtil.G_UseTargets(ent, activator);
+ GameUtil.G_FreeEdict(ent);
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_goal (1 0 1) (-8 -8 -8) (8 8 8) Counts a goal completed.
+ * These are single use targets.
+ */
+ static EntUseAdapter use_target_goal = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ GameBase.gi.sound(ent, Defines.CHAN_VOICE, ent.noise_index, 1,
+ Defines.ATTN_NORM, 0);
+
+ GameBase.level.found_goals++;
+
+ if (GameBase.level.found_goals == GameBase.level.total_goals)
+ GameBase.gi.configstring(Defines.CS_CDTRACK, "0");
+
+ GameUtil.G_UseTargets(ent, activator);
+ GameUtil.G_FreeEdict(ent);
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_explosion (1 0 0) (-8 -8 -8) (8 8 8) Spawns an explosion
+ * temporary entity when used.
+ *
+ * "delay" wait this long before going off "dmg" how much radius damage
+ * should be done, defaults to 0
+ */
+ static EntThinkAdapter target_explosion_explode = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float save;
+
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_EXPLOSION1);
+ GameBase.gi.WritePosition(self.s.origin);
+ GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS);
+
+ GameUtil.T_RadiusDamage(self, self.activator, self.dmg, null,
+ self.dmg + 40, Defines.MOD_EXPLOSIVE);
+
+ save = self.delay;
+ self.delay = 0;
+ GameUtil.G_UseTargets(self, self.activator);
+ self.delay = save;
+ return true;
+ }
+ };
+
+ static EntUseAdapter use_target_explosion = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.activator = activator;
+
+ if (0 == self.delay) {
+ target_explosion_explode.think(self);
+ return;
+ }
+
+ self.think = target_explosion_explode;
+ self.nextthink = GameBase.level.time + self.delay;
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_changelevel (1 0 0) (-8 -8 -8) (8 8 8) Changes level to
+ * "map" when fired
+ */
+ static EntUseAdapter use_target_changelevel = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (GameBase.level.intermissiontime != 0)
+ return; // already activated
+
+ if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value) {
+ if (GameBase.g_edicts[1].health <= 0)
+ return;
+ }
+
+ // if noexit, do a ton of damage to other
+ if (GameBase.deathmatch.value != 0
+ && 0 == ((int) GameBase.dmflags.value & Defines.DF_ALLOW_EXIT)
+ && other != GameBase.g_edicts[0] /* world */
+ ) {
+ GameUtil.T_Damage(other, self, self, Globals.vec3_origin,
+ other.s.origin, Globals.vec3_origin,
+ 10 * other.max_health, 1000, 0, Defines.MOD_EXIT);
+ return;
+ }
+
+ // if multiplayer, let everyone know who hit the exit
+ if (GameBase.deathmatch.value != 0) {
+ if (activator != null && activator.client != null)
+ GameBase.gi.bprintf(Defines.PRINT_HIGH,
+ activator.client.pers.netname
+ + " exited the level.\n");
+ }
+
+ // if going to a new unit, clear cross triggers
+ if (self.map.indexOf('*') > -1)
+ GameBase.game.serverflags &= ~(Defines.SFL_CROSS_TRIGGER_MASK);
+
+ PlayerHud.BeginIntermission(self);
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_splash (1 0 0) (-8 -8 -8) (8 8 8) Creates a particle splash
+ * effect when used.
+ *
+ * Set "sounds" to one of the following: 1) sparks 2) blue water 3) brown
+ * water 4) slime 5) lava 6) blood
+ *
+ * "count" how many pixels in the splash "dmg" if set, does a radius damage
+ * at this location when it splashes useful for lava/sparks
+ */
+ static EntUseAdapter use_target_splash = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_SPLASH);
+ GameBase.gi.WriteByte(self.count);
+ GameBase.gi.WritePosition(self.s.origin);
+ GameBase.gi.WriteDir(self.movedir);
+ GameBase.gi.WriteByte(self.sounds);
+ GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PVS);
+
+ if (self.dmg != 0)
+ GameUtil.T_RadiusDamage(self, activator, self.dmg, null,
+ self.dmg + 40, Defines.MOD_SPLASH);
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_spawner (1 0 0) (-8 -8 -8) (8 8 8) Set target to the type
+ * of entity you want spawned. Useful for spawning monsters and gibs in the
+ * factory levels.
+ *
+ * For monsters: Set direction to the facing you want it to have.
+ *
+ * For gibs: Set direction if you want it moving and speed how fast it
+ * should be moving otherwise it will just be dropped
+ */
+
+ static EntUseAdapter use_target_spawner = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ edict_t ent;
+
+ ent = GameUtil.G_Spawn();
+ ent.classname = self.target;
+ Math3D.VectorCopy(self.s.origin, ent.s.origin);
+ Math3D.VectorCopy(self.s.angles, ent.s.angles);
+ GameSpawn.ED_CallSpawn(ent);
+ GameBase.gi.unlinkentity(ent);
+ GameUtil.KillBox(ent);
+ GameBase.gi.linkentity(ent);
+ if (self.speed != 0)
+ Math3D.VectorCopy(self.movedir, ent.velocity);
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_blaster (1 0 0) (-8 -8 -8) (8 8 8) NOTRAIL NOEFFECTS Fires
+ * a blaster bolt in the set direction when triggered.
+ *
+ * dmg default is 15 speed default is 1000
+ */
+ public static EntUseAdapter use_target_blaster = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ int effect;
+
+ if ((self.spawnflags & 2) != 0)
+ effect = 0;
+ else if ((self.spawnflags & 1) != 0)
+ effect = Defines.EF_HYPERBLASTER;
+ else
+ effect = Defines.EF_BLASTER;
+
+ Fire.fire_blaster(self, self.s.origin, self.movedir, self.dmg,
+ (int) self.speed, Defines.EF_BLASTER,
+ Defines.MOD_TARGET_BLASTER != 0
+ /* true */
+ );
+ GameBase.gi.sound(self, Defines.CHAN_VOICE, self.noise_index, 1,
+ Defines.ATTN_NORM, 0);
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1
+ * trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 Once this
+ * trigger is touched/used, any trigger_crosslevel_target with the same
+ * trigger number is automatically used when a level is started within the
+ * same unit. It is OK to check multiple triggers. Message, delay, target,
+ * and killtarget also work.
+ */
+ public static EntUseAdapter trigger_crosslevel_trigger_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ GameBase.game.serverflags |= self.spawnflags;
+ GameUtil.G_FreeEdict(self);
+ }
+ };
+
+ /*
+ * QUAKED target_crosslevel_target (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1
+ * trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 Triggered
+ * by a trigger_crosslevel elsewhere within a unit. If multiple triggers are
+ * checked, all must be true. Delay, target and killtarget also work.
+ *
+ * "delay" delay before using targets if the trigger has been activated
+ * (default 1)
+ */
+ static EntThinkAdapter target_crosslevel_target_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.spawnflags == (GameBase.game.serverflags
+ & Defines.SFL_CROSS_TRIGGER_MASK & self.spawnflags)) {
+ GameUtil.G_UseTargets(self, self);
+ GameUtil.G_FreeEdict(self);
+ }
+ return true;
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE
+ * YELLOW ORANGE FAT When triggered, fires a laser. You can either set a
+ * target or a direction.
+ */
+ public static EntThinkAdapter target_laser_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ edict_t ignore;
+ float[] start = { 0, 0, 0 };
+ float[] end = { 0, 0, 0 };
+ trace_t tr;
+ float[] point = { 0, 0, 0 };
+ float[] last_movedir = { 0, 0, 0 };
+ int count;
+
+ if ((self.spawnflags & 0x80000000) != 0)
+ count = 8;
+ else
+ count = 4;
+
+ if (self.enemy != null) {
+ Math3D.VectorCopy(self.movedir, last_movedir);
+ Math3D
+ .VectorMA(self.enemy.absmin, 0.5f, self.enemy.size,
+ point);
+ Math3D.VectorSubtract(point, self.s.origin, self.movedir);
+ Math3D.VectorNormalize(self.movedir);
+ if (0 == Math3D.VectorCompare(self.movedir, last_movedir))
+ self.spawnflags |= 0x80000000;
+ }
+
+ ignore = self;
+ Math3D.VectorCopy(self.s.origin, start);
+ Math3D.VectorMA(start, 2048, self.movedir, end);
+ while (true) {
+ tr = GameBase.gi.trace(start, null, null, end, ignore,
+ Defines.CONTENTS_SOLID | Defines.CONTENTS_MONSTER
+ | Defines.CONTENTS_DEADMONSTER);
+
+ if (tr.ent == null)
+ break;
+
+ // hurt it if we can
+ if ((tr.ent.takedamage != 0)
+ && 0 == (tr.ent.flags & Defines.FL_IMMUNE_LASER))
+ GameUtil.T_Damage(tr.ent, self, self.activator,
+ self.movedir, tr.endpos, Globals.vec3_origin,
+ self.dmg, 1, Defines.DAMAGE_ENERGY,
+ Defines.MOD_TARGET_LASER);
+
+ // if we hit something that's not a monster or player or is
+ // immune to lasers, we're done
+ if (0 == (tr.ent.svflags & Defines.SVF_MONSTER)
+ && (null == tr.ent.client)) {
+ if ((self.spawnflags & 0x80000000) != 0) {
+ self.spawnflags &= ~0x80000000;
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_LASER_SPARKS);
+ GameBase.gi.WriteByte(count);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.WriteDir(tr.plane.normal);
+ GameBase.gi.WriteByte(self.s.skinnum);
+ GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
+ }
+ break;
+ }
+
+ ignore = tr.ent;
+ Math3D.VectorCopy(tr.endpos, start);
+ }
+
+ Math3D.VectorCopy(tr.endpos, self.s.old_origin);
+
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+ return true;
+ }
+ };
+
+ public static EntUseAdapter target_laser_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.activator = activator;
+ if ((self.spawnflags & 1) != 0)
+ GameTarget.target_laser_off(self);
+ else
+ GameTarget.target_laser_on(self);
+ }
+ };
+
+ static EntThinkAdapter target_laser_start = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ edict_t ent;
+
+ self.movetype = Defines.MOVETYPE_NONE;
+ self.solid = Defines.SOLID_NOT;
+ self.s.renderfx |= Defines.RF_BEAM | Defines.RF_TRANSLUCENT;
+ self.s.modelindex = 1; // must be non-zero
+
+ // set the beam diameter
+ if ((self.spawnflags & 64) != 0)
+ self.s.frame = 16;
+ else
+ self.s.frame = 4;
+
+ // set the color
+ if ((self.spawnflags & 2) != 0)
+ self.s.skinnum = 0xf2f2f0f0;
+ else if ((self.spawnflags & 4) != 0)
+ self.s.skinnum = 0xd0d1d2d3;
+ else if ((self.spawnflags & 8) != 0)
+ self.s.skinnum = 0xf3f3f1f1;
+ else if ((self.spawnflags & 16) != 0)
+ self.s.skinnum = 0xdcdddedf;
+ else if ((self.spawnflags & 32) != 0)
+ self.s.skinnum = 0xe0e1e2e3;
+
+ if (null == self.enemy) {
+ if (self.target != null) {
+ ent = GameBase.G_Find(null, GameBase.findByTarget,
+ self.target).o;
+ if (ent == null)
+ GameBase.gi.dprintf(self.classname + " at "
+ + Lib.vtos(self.s.origin) + ": " + self.target
+ + " is a bad target\n");
+ self.enemy = ent;
+ } else {
+ GameBase.G_SetMovedir(self.s.angles, self.movedir);
+ }
+ }
+ self.use = target_laser_use;
+ self.think = target_laser_think;
+
+ if (0 == self.dmg)
+ self.dmg = 1;
+
+ Math3D.VectorSet(self.mins, -8, -8, -8);
+ Math3D.VectorSet(self.maxs, 8, 8, 8);
+ GameBase.gi.linkentity(self);
+
+ if ((self.spawnflags & 1) != 0)
+ GameTarget.target_laser_on(self);
+ else
+ GameTarget.target_laser_off(self);
+ return true;
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_lightramp (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE speed How
+ * many seconds the ramping will take message two letters; starting
+ * lightlevel and ending lightlevel
+ */
+
+ static EntThinkAdapter target_lightramp_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ char style[] = { ' ', ' ' };
+
+ style[0] = (char) ('a' + (int) (self.movedir[0] + (GameBase.level.time - self.timestamp)
+ / Defines.FRAMETIME * self.movedir[2]));
+ style[1] = 0;
+ GameBase.gi.configstring(Defines.CS_LIGHTS + self.enemy.style,
+ new String(style));
+
+ if ((GameBase.level.time - self.timestamp) < self.speed) {
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+ } else if ((self.spawnflags & 1) != 0) {
+ char temp;
+
+ temp = (char) self.movedir[0];
+ self.movedir[0] = self.movedir[1];
+ self.movedir[1] = temp;
+ self.movedir[2] *= -1;
+ }
+
+ return true;
+ }
+ };
+
+ static EntUseAdapter target_lightramp_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (self.enemy == null) {
+ edict_t e;
+
+ // check all the targets
+ e = null;
+ EdictIterator es = null;
+
+ while (true) {
+ es = GameBase
+ .G_Find(es, GameBase.findByTarget, self.target);
+ e = es.o;
+
+ if (e == null)
+ break;
+ if (Lib.strcmp(e.classname, "light") != 0) {
+ GameBase.gi.dprintf(self.classname + " at "
+ + Lib.vtos(self.s.origin));
+ GameBase.gi.dprintf("target " + self.target + " ("
+ + e.classname + " at " + Lib.vtos(e.s.origin)
+ + ") is not a light\n");
+ } else {
+ self.enemy = e;
+ }
+ }
+
+ if (null == self.enemy) {
+ GameBase.gi.dprintf(self.classname + " target "
+ + self.target + " not found at "
+ + Lib.vtos(self.s.origin) + "\n");
+ GameUtil.G_FreeEdict(self);
+ return;
+ }
+ }
+
+ self.timestamp = GameBase.level.time;
+ target_lightramp_think.think(self);
+ }
+ };
+
+ //==========================================================
+
+ /*
+ * QUAKED target_earthquake (1 0 0) (-8 -8 -8) (8 8 8) When triggered, this
+ * initiates a level-wide earthquake. All players and monsters are affected.
+ * "speed" severity of the quake (default:200) "count" duration of the quake
+ * (default:5)
+ */
+
+ static EntThinkAdapter target_earthquake_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ int i;
+ edict_t e;
+
+ if (self.last_move_time < GameBase.level.time) {
+ GameBase.gi.positioned_sound(self.s.origin, self,
+ Defines.CHAN_AUTO, self.noise_index, 1.0f,
+ Defines.ATTN_NONE, 0);
+ self.last_move_time = GameBase.level.time + 0.5f;
+ }
+
+ for (i = 1; i < GameBase.num_edicts; i++) {
+ e = GameBase.g_edicts[i];
+
+ if (!e.inuse)
+ continue;
+ if (null == e.client)
+ continue;
+ if (null == e.groundentity)
+ continue;
+
+ e.groundentity = null;
+ e.velocity[0] += Lib.crandom() * 150;
+ e.velocity[1] += Lib.crandom() * 150;
+ e.velocity[2] = self.speed * (100.0f / e.mass);
+ }
+
+ if (GameBase.level.time < self.timestamp)
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+
+ return true;
+ }
+ };
+
+ static EntUseAdapter target_earthquake_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.timestamp = GameBase.level.time + self.count;
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+ self.activator = activator;
+ self.last_move_time = 0;
+ }
+ };
+} \ No newline at end of file