aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/game
diff options
context:
space:
mode:
authorHolger Zickner <[email protected]>2004-07-07 19:59:59 +0000
committerHolger Zickner <[email protected]>2004-07-07 19:59:59 +0000
commit6e23fc1074d1f0c2c2812f4c2e663f5a21a43c20 (patch)
tree46ecc6d0255c874ba4cd26dc3d0733f785019896 /src/jake2/game
import of Jake2 version sunrisesunrise
Diffstat (limited to 'src/jake2/game')
-rw-r--r--src/jake2/game/AIAdapter.java29
-rw-r--r--src/jake2/game/BigEndianHandler.java57
-rw-r--r--src/jake2/game/Cmd.java1227
-rw-r--r--src/jake2/game/EdictFindFilter.java32
-rw-r--r--src/jake2/game/EdictIterator.java36
-rw-r--r--src/jake2/game/EndianHandler.java77
-rw-r--r--src/jake2/game/EntBlockedAdapter.java30
-rw-r--r--src/jake2/game/EntDieAdapter.java29
-rw-r--r--src/jake2/game/EntDodgeAdapter.java29
-rw-r--r--src/jake2/game/EntInteractAdapter.java31
-rw-r--r--src/jake2/game/EntPainAdapter.java29
-rw-r--r--src/jake2/game/EntThinkAdapter.java31
-rw-r--r--src/jake2/game/EntTouchAdapter.java30
-rw-r--r--src/jake2/game/EntUseAdapter.java30
-rw-r--r--src/jake2/game/Fire.java584
-rw-r--r--src/jake2/game/Game.java29
-rw-r--r--src/jake2/game/GameAI.java3520
-rw-r--r--src/jake2/game/GameBase.java824
-rw-r--r--src/jake2/game/GameFunc.java2027
-rw-r--r--src/jake2/game/GameMisc.java1583
-rw-r--r--src/jake2/game/GamePWeapon.java1437
-rw-r--r--src/jake2/game/GameSVCmds.java306
-rw-r--r--src/jake2/game/GameSave.java733
-rw-r--r--src/jake2/game/GameSpawn.java803
-rw-r--r--src/jake2/game/GameTarget.java829
-rw-r--r--src/jake2/game/GameTrigger.java574
-rw-r--r--src/jake2/game/GameTurret.java430
-rw-r--r--src/jake2/game/GameUtil.java1840
-rw-r--r--src/jake2/game/GameWeapon.java566
-rw-r--r--src/jake2/game/Info.java263
-rw-r--r--src/jake2/game/ItemDropAdapter.java29
-rw-r--r--src/jake2/game/ItemUseAdapter.java29
-rw-r--r--src/jake2/game/LittleEndianHandler.java56
-rw-r--r--src/jake2/game/M_Actor.java1129
-rw-r--r--src/jake2/game/M_Berserk.java724
-rw-r--r--src/jake2/game/M_Boss2.java899
-rw-r--r--src/jake2/game/M_Boss3.java76
-rw-r--r--src/jake2/game/M_Boss31.java1012
-rw-r--r--src/jake2/game/M_Boss32.java1469
-rw-r--r--src/jake2/game/M_Brain.java944
-rw-r--r--src/jake2/game/M_Chick.java987
-rw-r--r--src/jake2/game/M_Flash.java707
-rw-r--r--src/jake2/game/M_Flipper.java627
-rw-r--r--src/jake2/game/M_Float.java1007
-rw-r--r--src/jake2/game/M_Flyer.java808
-rw-r--r--src/jake2/game/M_Gladiator.java570
-rw-r--r--src/jake2/game/M_Gunner.java837
-rw-r--r--src/jake2/game/M_Hover.java805
-rw-r--r--src/jake2/game/M_Infantry.java814
-rw-r--r--src/jake2/game/M_Insane.java959
-rw-r--r--src/jake2/game/M_Medic.java1006
-rw-r--r--src/jake2/game/M_Mutant.java834
-rw-r--r--src/jake2/game/M_Parasite.java675
-rw-r--r--src/jake2/game/M_Player.java230
-rw-r--r--src/jake2/game/M_Rider.java29
-rw-r--r--src/jake2/game/M_Soldier.java1706
-rw-r--r--src/jake2/game/M_Supertank.java964
-rw-r--r--src/jake2/game/M_Tank.java1143
-rw-r--r--src/jake2/game/Monster.java368
-rw-r--r--src/jake2/game/PlayerClient.java1566
-rw-r--r--src/jake2/game/PlayerHud.java573
-rw-r--r--src/jake2/game/PlayerTrail.java151
-rw-r--r--src/jake2/game/PlayerView.java1054
-rw-r--r--src/jake2/game/SuperAdapter.java69
-rw-r--r--src/jake2/game/Swap.java46
-rw-r--r--src/jake2/game/client_persistant_t.java150
-rw-r--r--src/jake2/game/client_respawn_t.java71
-rw-r--r--src/jake2/game/cmdalias_t.java32
-rw-r--r--src/jake2/game/cmodel_t.java32
-rw-r--r--src/jake2/game/cplane_t.java57
-rw-r--r--src/jake2/game/csurface_t.java29
-rw-r--r--src/jake2/game/cvar_t.java40
-rw-r--r--src/jake2/game/edict_t.java469
-rw-r--r--src/jake2/game/entity_state_t.java85
-rw-r--r--src/jake2/game/field_t.java44
-rw-r--r--src/jake2/game/game_export_t.java118
-rw-r--r--src/jake2/game/game_import_t.java237
-rw-r--r--src/jake2/game/game_locals_t.java95
-rw-r--r--src/jake2/game/gclient_t.java323
-rw-r--r--src/jake2/game/gitem_armor_t.java46
-rw-r--r--src/jake2/game/gitem_t.java142
-rw-r--r--src/jake2/game/level_locals_t.java69
-rw-r--r--src/jake2/game/link_t.java33
-rw-r--r--src/jake2/game/mapsurface_t.java37
-rw-r--r--src/jake2/game/mframe_t.java36
-rw-r--r--src/jake2/game/mmove_t.java38
-rw-r--r--src/jake2/game/monsterinfo_t.java63
-rw-r--r--src/jake2/game/moveinfo_t.java54
-rw-r--r--src/jake2/game/player_state_t.java165
-rw-r--r--src/jake2/game/pmove_state_t.java130
-rw-r--r--src/jake2/game/pmove_t.java83
-rw-r--r--src/jake2/game/pushed_t.java31
-rw-r--r--src/jake2/game/spawn_t.java34
-rw-r--r--src/jake2/game/spawn_temp_t.java129
-rw-r--r--src/jake2/game/trace_t.java54
-rw-r--r--src/jake2/game/usercmd_t.java86
96 files changed, 45959 insertions, 0 deletions
diff --git a/src/jake2/game/AIAdapter.java b/src/jake2/game/AIAdapter.java
new file mode 100644
index 0000000..f6bd6cb
--- /dev/null
+++ b/src/jake2/game/AIAdapter.java
@@ -0,0 +1,29 @@
+/*
+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 11.11.2003 by RST.
+// $Id: AIAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class AIAdapter extends SuperAdapter {
+ public void ai(edict_t self, float dist) {
+ }
+}
diff --git a/src/jake2/game/BigEndianHandler.java b/src/jake2/game/BigEndianHandler.java
new file mode 100644
index 0000000..493410c
--- /dev/null
+++ b/src/jake2/game/BigEndianHandler.java
@@ -0,0 +1,57 @@
+/*
+ * BigEndianHandler.java
+ * Copyright (C) 2003
+ *
+ * $Id: BigEndianHandler.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+package jake2.game;
+
+
+/**
+ * BigEndianHandler
+ */
+public final class BigEndianHandler extends EndianHandler {
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#BigFloat(float)
+ */
+ public float BigFloat(float f) {
+ return f;
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#BigShort(short)
+ */
+ public short BigShort(short s) {
+ return s;
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#BigLong(int)
+ */
+ public int BigLong(int i) {
+ return i;
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#LittleFloat(float)
+ */
+ public float LittleFloat(float f) {
+ return swapFloat(f);
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#LittleShort(short)
+ */
+ public short LittleShort(short s) {
+ return swapShort(s);
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#LittleLong(int)
+ */
+ public int LittleLong(int i) {
+ return swapInt(i);
+ }
+
+}
diff --git a/src/jake2/game/Cmd.java b/src/jake2/game/Cmd.java
new file mode 100644
index 0000000..8292d25
--- /dev/null
+++ b/src/jake2/game/Cmd.java
@@ -0,0 +1,1227 @@
+/*
+ * Cmd.java
+ * Copyright (C) 2003
+ *
+ * $Id: Cmd.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.game;
+
+import jake2.Defines;
+import jake2.Globals;
+import jake2.qcommon.*;
+import jake2.util.Lib;
+
+import java.util.Arrays;
+
+/**
+ * Cmd
+ */
+public final class Cmd extends PlayerView {
+
+ static xcommand_t List_f = new xcommand_t() {
+ public void execute() {
+ cmd_function_t cmd = Cmd.cmd_functions;
+ int i = 0;
+
+ while (cmd != null) {
+ Com.Printf(cmd.name + '\n');
+ i++;
+ cmd = cmd.next;
+ }
+ Com.Printf(i + " commands\n");
+ }
+ };
+
+ static xcommand_t Exec_f = new xcommand_t() {
+ public void execute() {
+ if (Cmd.Argc() != 2) {
+ Com.Printf("exec <filename> : execute a script file\n");
+ return;
+ }
+
+ byte[] f = null;
+ f = FS.LoadFile(Cmd.Argv(1));
+ if (f == null) {
+ Com.Printf("couldn't exec " + Cmd.Argv(1) + "\n");
+ return;
+ }
+ Com.Printf("execing " + Cmd.Argv(1) + "\n");
+
+ Cbuf.InsertText(new String(f));
+
+ FS.FreeFile(f);
+ }
+ };
+ static xcommand_t Echo_f = new xcommand_t() {
+ public void execute() {
+ for (int i = 1; i < Cmd.Argc(); i++) {
+ Com.Printf(Cmd.Argv(i) + " ");
+ }
+ Com.Printf("'\n");
+ }
+ };
+
+ static xcommand_t Alias_f = new xcommand_t() {
+ public void execute() {
+ cmdalias_t a = null;
+ if (Cmd.Argc() == 1) {
+ Com.Printf("Current alias commands:\n");
+ for (a = Globals.cmd_alias; a != null; a = a.next) {
+ Com.Printf(a.name + " : " + a.value);
+ }
+ return;
+ }
+
+ String s = Cmd.Argv(1);
+ if (s.length() > Globals.MAX_ALIAS_NAME) {
+ Com.Printf("Alias name is too long\n");
+ return;
+ }
+
+ // if the alias already exists, reuse it
+ for (a = Globals.cmd_alias; a != null; a = a.next) {
+ if (s.equalsIgnoreCase(a.name)) {
+ a.value = null;
+ break;
+ }
+ }
+
+ if (a == null) {
+ a = new cmdalias_t();
+ a.next = Globals.cmd_alias;
+ Globals.cmd_alias = a;
+ }
+ a.name = s;
+
+ // copy the rest of the command line
+ String cmd = "";
+ int c = Cmd.Argc();
+ for (int i = 2; i < c; i++) {
+ cmd = cmd + Cmd.Argv(i);
+ if (i != (c - 1))
+ cmd = cmd + " ";
+ }
+ cmd = cmd + "\n";
+
+ a.value = cmd;
+ }
+ };
+
+ public static xcommand_t Wait_f = new xcommand_t() {
+ public void execute() {
+ Globals.cmd_wait = true;
+ }
+ };
+
+ public static cmd_function_t cmd_functions = null;
+ public static int cmd_argc;
+ public static String[] cmd_argv = new String[Globals.MAX_STRING_TOKENS];
+ public static String cmd_args;
+ public static final int ALIAS_LOOP_COUNT = 16;
+
+ /**
+ * register our commands
+ */
+ public static void Init() {
+
+ Cmd.AddCommand("exec", Exec_f);
+ Cmd.AddCommand("echo", Echo_f);
+ Cmd.AddCommand("cmdlist", List_f);
+ Cmd.AddCommand("alias", Alias_f);
+ Cmd.AddCommand("wait", Wait_f);
+ }
+
+ private static char expanded[] = new char[MAX_STRING_CHARS];
+ private static char temporary[] = new char[MAX_STRING_CHARS];
+ /*
+ ======================
+ Cmd_MacroExpandString
+ ======================
+ */
+ public static char[] MacroExpandString(char text[], int len) {
+ int i, j, count;
+ boolean inquote;
+
+ char scan[];
+
+ String token;
+ inquote = false;
+
+ scan = text;
+
+ if (len >= MAX_STRING_CHARS) {
+ Com.Printf("Line exceeded " + MAX_STRING_CHARS + " chars, discarded.\n");
+ return null;
+ }
+
+ count = 0;
+
+ for (i = 0; i < len; i++) {
+ if (scan[i] == '"')
+ inquote = !inquote;
+
+ if (inquote)
+ continue; // don't expand inside quotes
+
+ if (scan[i] != '$')
+ continue;
+
+ // scan out the complete macro, without $
+ Com.ParseHelp ph = new Com.ParseHelp(text, i + 1);
+ token = Com.Parse(ph);
+
+ if (ph.data == null)
+ continue;
+
+ token = Cvar.VariableString(token);
+
+ j = strlen(token);
+
+ len += j;
+
+ if (len >= MAX_STRING_CHARS) {
+ Com.Printf("Expanded line exceeded " + MAX_STRING_CHARS + " chars, discarded.\n");
+ return null;
+ }
+
+ //strncpy(temporary, scan, i);
+ System.arraycopy(scan, 0, temporary, 0, i);
+
+ //strcpy(temporary + i, token);
+ System.arraycopy(token, 0, temporary, i, token.length());
+
+ //strcpy(temporary + i + j, start);
+ System.arraycopy(ph.data, ph.index, temporary, i + j, len - ph.index);
+
+ //strcpy(expanded, temporary);
+ System.arraycopy(temporary, 0, expanded, 0, 0);
+ scan = expanded;
+ i--;
+
+ if (++count == 100) {
+ Com.Printf("Macro expansion loop, discarded.\n");
+ return null;
+ }
+ }
+
+ if (inquote) {
+ Com.Printf("Line has unmatched quote, discarded.\n");
+ return null;
+ }
+
+ return scan;
+ }
+
+ /*
+ ============
+ Cmd_TokenizeString
+
+ Parses the given string into command line tokens.
+ $Cvars will be expanded unless they are in a quoted token
+ ============
+ */
+ public static void TokenizeString(char text[], boolean macroExpand) {
+ int i;
+ String com_token;
+
+ cmd_argc = 0;
+
+ int len = strlen(text);
+
+ // macro expand the text
+ if (macroExpand)
+ text = MacroExpandString(text, len);
+
+ if (text == null)
+ return;
+
+ len = strlen(text);
+
+ Com.ParseHelp ph = new Com.ParseHelp(text);
+
+ while (true) {
+
+ // skip whitespace up to a /n
+ char c = ph.skipwhitestoeol();
+
+ if (c == '\n') { // a newline seperates commands in the buffer
+ c = ph.nextchar();
+ break;
+ }
+
+ if (c == 0)
+ return;
+
+ // set cmd_args to everything after the first arg
+ if (cmd_argc == 1) {
+ cmd_args = new String(text, ph.index, len - ph.index);
+ cmd_args.trim();
+ }
+
+ com_token = Com.Parse(ph);
+
+ if (com_token.length() == 0)
+ return;
+
+ if (cmd_argc < MAX_STRING_TOKENS) {
+ cmd_argv[cmd_argc] = com_token;
+ cmd_argc++;
+ }
+ }
+ }
+
+ public static void AddCommand(String cmd_name, xcommand_t function) {
+ cmd_function_t cmd;
+ //Com.DPrintf("Cmd_AddCommand: " + cmd_name + "\n");
+ // fail if the command is a variable name
+ if ((Cvar.VariableString(cmd_name)).length() > 0) {
+ Com.Printf("Cmd_AddCommand: " + cmd_name + " already defined as a var\n");
+ return;
+ }
+
+ // fail if the command already exists
+ for (cmd = cmd_functions; cmd != null; cmd = cmd.next) {
+ if (cmd_name.equals(cmd.name)) {
+ Com.Printf("Cmd_AddCommand: " + cmd_name + " already defined\n");
+ return;
+ }
+ }
+
+ cmd = new cmd_function_t();
+ cmd.name = cmd_name;
+
+ cmd.function = function;
+ cmd.next = cmd_functions;
+ cmd_functions = cmd;
+ }
+
+ /*
+ ============
+ Cmd_RemoveCommand
+ ============
+ */
+ public static void RemoveCommand(String cmd_name) {
+ cmd_function_t cmd, back = null;
+
+ back = cmd = cmd_functions;
+
+ while (true) {
+
+ if (cmd == null) {
+ Com.Printf("Cmd_RemoveCommand: " + cmd_name + " not added\n");
+ return;
+ }
+ if (0 == strcmp(cmd_name, cmd.name)) {
+ if (cmd == cmd_functions)
+ cmd_functions = cmd.next;
+ else
+ back.next = cmd.next;
+ return;
+ }
+ back = cmd;
+ cmd = cmd.next;
+ }
+ }
+
+ /*
+ ============
+ Cmd_Exists
+ ============
+ */
+ public static boolean Exists(String cmd_name) {
+ cmd_function_t cmd;
+
+ for (cmd = cmd_functions; cmd != null; cmd = cmd.next) {
+ if (0 == strcmp(cmd_name, cmd.name))
+ return true;
+ }
+
+ return false;
+ }
+
+ public static int Argc() {
+ return cmd_argc;
+ }
+
+ public static String Argv(int i) {
+ if (i < 0 || i >= cmd_argc)
+ return "";
+ return cmd_argv[i];
+ }
+
+ public static String Args() {
+ return new String(cmd_args);
+ }
+
+ /*
+ ============
+ Cmd_ExecuteString
+
+ A complete command line has been parsed, so try to execute it
+ FIXME: lookupnoadd the token to speed search?
+ ============
+ */
+ public static void ExecuteString(String text) {
+
+ cmd_function_t cmd;
+ cmdalias_t a;
+
+ TokenizeString(text.toCharArray(), true);
+
+// if (Argc() > 0) {
+// Com.DPrintf("tokenized:");
+// for (int xxx = 0; xxx < Argc(); xxx++)
+// Com.DPrintf("[" + Argv(xxx) + "]");
+//
+// Com.DPrintf("\n");
+// }
+ //System.out.println("tokenized[" + Argv(0) + "]" + "[" + Argv(1) + "]");
+ // execute the command line
+ if (Argc() == 0)
+ return; // no tokens
+
+ // check functions
+ for (cmd = cmd_functions; cmd != null; cmd = cmd.next) {
+ if (cmd_argv[0].equalsIgnoreCase(cmd.name)) {
+ if (null == cmd.function) { // forward to server command
+ Cmd.ExecuteString("cmd " + text);
+ }
+ else
+ try {
+ cmd.function.execute();
+ }
+ catch (Exception e) {
+ System.err.println("Exception in executing a command " + cmd.name + ":");
+ e.printStackTrace();
+ }
+ return;
+ }
+ }
+
+ // check alias
+ for (a = cmd_alias; a != null; a = a.next) {
+
+ if (cmd_argv[0].equalsIgnoreCase(a.name)) {
+
+ if (++alias_count == ALIAS_LOOP_COUNT) {
+ Com.Printf("ALIAS_LOOP_COUNT\n");
+ return;
+ }
+ Cbuf.InsertText(a.value);
+ return;
+ }
+ }
+
+ // check cvars
+ if (Cvar.Command())
+ return;
+
+ // send it as a server command if we are connected
+ Cmd.ForwardToServer();
+ }
+
+ /*
+ ==================
+ Cmd_Give_f
+
+ Give items to a client
+ ==================
+ */
+ public static void Give_f(edict_t ent) {
+ String name;
+ gitem_t it;
+ int index;
+ int i;
+ boolean give_all;
+ edict_t it_ent;
+
+ if (GameBase.deathmatch.value == 0 && GameBase.sv_cheats.value == 0) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+ return;
+ }
+
+ name = GameBase.gi.args();
+
+ if (0 == Lib.Q_stricmp(name, "all"))
+ give_all = true;
+ else
+ give_all = false;
+
+ if (give_all || 0 == Lib.Q_stricmp(GameBase.gi.argv(1), "health")) {
+ if (GameBase.gi.argc() == 3)
+ ent.health = Lib.atoi(GameBase.gi.argv(2));
+ else
+ ent.health = ent.max_health;
+ if (!give_all)
+ return;
+ }
+
+ if (give_all || 0 == Lib.Q_stricmp(name, "weapons")) {
+ for (i = 0; i < GameBase.game.num_items; i++) {
+ it = GameAI.itemlist[i];
+ if (null == it.pickup)
+ continue;
+ if (0 == (it.flags & Defines.IT_WEAPON))
+ continue;
+ ent.client.pers.inventory[i] += 1;
+ }
+ if (!give_all)
+ return;
+ }
+
+ if (give_all || 0 == Lib.Q_stricmp(name, "ammo")) {
+ for (i = 0; i < GameBase.game.num_items; i++) {
+ it = GameAI.itemlist[i];
+ if (null == it.pickup)
+ continue;
+ if (0 == (it.flags & Defines.IT_AMMO))
+ continue;
+ GameAI.Add_Ammo(ent, it, 1000);
+ }
+ if (!give_all)
+ return;
+ }
+
+ if (give_all || Lib.Q_stricmp(name, "armor") == 0) {
+ gitem_armor_t info;
+
+ it = GameUtil.FindItem("Jacket Armor");
+ ent.client.pers.inventory[GameUtil.ITEM_INDEX(it)] = 0;
+
+ it = GameUtil.FindItem("Combat Armor");
+ ent.client.pers.inventory[GameUtil.ITEM_INDEX(it)] = 0;
+
+ it = GameUtil.FindItem("Body Armor");
+ info = (gitem_armor_t) it.info;
+ ent.client.pers.inventory[GameUtil.ITEM_INDEX(it)] = info.max_count;
+
+ if (!give_all)
+ return;
+ }
+
+ if (give_all || Lib.Q_stricmp(name, "Power Shield") == 0) {
+ it = GameUtil.FindItem("Power Shield");
+ it_ent = GameUtil.G_Spawn();
+ it_ent.classname = it.classname;
+ GameAI.SpawnItem(it_ent, it);
+ GameAI.Touch_Item(it_ent, ent, null, null);
+ if (it_ent.inuse)
+ GameUtil.G_FreeEdict(it_ent);
+
+ if (!give_all)
+ return;
+ }
+
+ if (give_all) {
+ for (i = 0; i < GameBase.game.num_items; i++) {
+ it = GameAI.itemlist[i];
+ if (it.pickup != null)
+ continue;
+ if ((it.flags & (Defines.IT_ARMOR | Defines.IT_WEAPON | Defines.IT_AMMO)) != 0)
+ continue;
+ ent.client.pers.inventory[i] = 1;
+ }
+ return;
+ }
+
+ it = GameUtil.FindItem(name);
+ if (it == null) {
+ name = GameBase.gi.argv(1);
+ it = GameUtil.FindItem(name);
+ if (it == null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "unknown item\n");
+ return;
+ }
+ }
+
+ if (it.pickup == null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "non-pickup item\n");
+ return;
+ }
+
+ index = GameUtil.ITEM_INDEX(it);
+
+ if ((it.flags & Defines.IT_AMMO) != 0) {
+ if (GameBase.gi.argc() == 3)
+ ent.client.pers.inventory[index] = Lib.atoi(GameBase.gi.argv(2));
+ else
+ ent.client.pers.inventory[index] += it.quantity;
+ }
+ else {
+ it_ent = GameUtil.G_Spawn();
+ it_ent.classname = it.classname;
+ GameAI.SpawnItem(it_ent, it);
+ GameAI.Touch_Item(it_ent, ent, null, null);
+ if (it_ent.inuse)
+ GameUtil.G_FreeEdict(it_ent);
+ }
+ }
+
+ /*
+ ==================
+ Cmd_God_f
+
+ Sets client to godmode
+
+ argv(0) god
+ ==================
+ */
+ public static void God_f(edict_t ent) {
+ String msg;
+
+ if (GameBase.deathmatch.value == 0 && GameBase.sv_cheats.value == 0) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+ return;
+ }
+
+ ent.flags ^= Defines.FL_GODMODE;
+ if (0 == (ent.flags & Defines.FL_GODMODE))
+ msg = "godmode OFF\n";
+ else
+ msg = "godmode ON\n";
+
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, msg);
+ }
+
+ /*
+ ==================
+ Cmd_Notarget_f
+
+ Sets client to notarget
+
+ argv(0) notarget
+ ==================
+ */
+ public static void Notarget_f(edict_t ent) {
+ String msg;
+
+ if (GameBase.deathmatch.value != 0 && GameBase.sv_cheats.value == 0) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+ return;
+ }
+
+ ent.flags ^= Defines.FL_NOTARGET;
+ if (0 == (ent.flags & Defines.FL_NOTARGET))
+ msg = "notarget OFF\n";
+ else
+ msg = "notarget ON\n";
+
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, msg);
+ }
+
+ /*
+ ==================
+ Cmd_Noclip_f
+
+ argv(0) noclip
+ ==================
+ */
+ public static void Noclip_f(edict_t ent) {
+ String msg;
+
+ if (GameBase.deathmatch.value != 0 && GameBase.sv_cheats.value == 0) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
+ return;
+ }
+
+ if (ent.movetype == Defines.MOVETYPE_NOCLIP) {
+ ent.movetype = Defines.MOVETYPE_WALK;
+ msg = "noclip OFF\n";
+ }
+ else {
+ ent.movetype = Defines.MOVETYPE_NOCLIP;
+ msg = "noclip ON\n";
+ }
+
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, msg);
+ }
+
+ /*
+ ==================
+ Cmd_Use_f
+
+ Use an inventory item
+ ==================
+ */
+ public static void Use_f(edict_t ent) {
+ int index;
+ gitem_t it;
+ String s;
+
+ s = GameBase.gi.args();
+ it = GameUtil.FindItem(s);
+ if (it != null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "unknown item: " + s + "\n");
+ return;
+ }
+ if (it.use == null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Item is not usable.\n");
+ return;
+ }
+ index = GameUtil.ITEM_INDEX(it);
+ if (0 == ent.client.pers.inventory[index]) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Out of item: " + s + "\n");
+ return;
+ }
+
+ it.use.use(ent, it);
+ }
+
+ /*
+ ==================
+ Cmd_Drop_f
+
+ Drop an inventory item
+ ==================
+ */
+ public static void Drop_f(edict_t ent) {
+ int index;
+ gitem_t it;
+ String s;
+
+ s = GameBase.gi.args();
+ it = GameUtil.FindItem(s);
+ if (it == null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "unknown item: " + s + "\n");
+ return;
+ }
+ if (it.drop == null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Item is not dropable.\n");
+ return;
+ }
+ index = GameUtil.ITEM_INDEX(it);
+ if (0 == ent.client.pers.inventory[index]) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Out of item: " + s + "\n");
+ return;
+ }
+
+ it.drop.drop(ent, it);
+ }
+
+ /*
+ =================
+ Cmd_Inven_f
+ =================
+ */
+ public static void Inven_f(edict_t ent) {
+ int i;
+ gclient_t cl;
+
+ cl = ent.client;
+
+ cl.showscores = false;
+ cl.showhelp = false;
+
+ if (cl.showinventory) {
+ cl.showinventory = false;
+ return;
+ }
+
+ cl.showinventory = true;
+
+ GameBase.gi.WriteByte(Defines.svc_inventory);
+ for (i = 0; i < Defines.MAX_ITEMS; i++) {
+ GameBase.gi.WriteShort(cl.pers.inventory[i]);
+ }
+ GameBase.gi.unicast(ent, true);
+ }
+
+ /*
+ =================
+ Cmd_InvUse_f
+ =================
+ */
+ public static void InvUse_f(edict_t ent) {
+ gitem_t it;
+
+ GameAI.ValidateSelectedItem(ent);
+
+ if (ent.client.pers.selected_item == -1) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "No item to use.\n");
+ return;
+ }
+
+ it = GameAI.itemlist[ent.client.pers.selected_item];
+ if (it.use == null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Item is not usable.\n");
+ return;
+ }
+ it.use.use(ent, it);
+ }
+
+ /*
+ =================
+ Cmd_WeapPrev_f
+ =================
+ */
+ public static void WeapPrev_f(edict_t ent) {
+ gclient_t cl;
+ int i, index;
+ gitem_t it;
+ int selected_weapon;
+
+ cl = ent.client;
+
+ if (cl.pers.weapon == null)
+ return;
+
+ selected_weapon = GameUtil.ITEM_INDEX(cl.pers.weapon);
+
+ // scan for the next valid one
+ for (i = 1; i <= Defines.MAX_ITEMS; i++) {
+ index = (selected_weapon + i) % Defines.MAX_ITEMS;
+ if (0 == cl.pers.inventory[index])
+ continue;
+
+ it = GameAI.itemlist[index];
+ if (it.use == null)
+ continue;
+
+ if (0 == (it.flags & Defines.IT_WEAPON))
+ continue;
+ it.use.use(ent, it);
+ if (cl.pers.weapon == it)
+ return; // successful
+ }
+ }
+
+ /*
+ =================
+ Cmd_WeapNext_f
+ =================
+ */
+ public static void WeapNext_f(edict_t ent) {
+ gclient_t cl;
+ int i, index;
+ gitem_t it;
+ int selected_weapon;
+
+ cl = ent.client;
+
+ if (null == cl.pers.weapon)
+ return;
+
+ selected_weapon = GameUtil.ITEM_INDEX(cl.pers.weapon);
+
+ // scan for the next valid one
+ for (i = 1; i <= Defines.MAX_ITEMS; i++) {
+ index = (selected_weapon + Defines.MAX_ITEMS - i) % Defines.MAX_ITEMS;
+ if (0 == cl.pers.inventory[index])
+ continue;
+ it = GameAI.itemlist[index];
+ if (null == it.use)
+ continue;
+ if (0 == (it.flags & Defines.IT_WEAPON))
+ continue;
+ it.use.use(ent, it);
+ if (cl.pers.weapon == it)
+ return; // successful
+ }
+ }
+
+ /*
+ =================
+ Cmd_WeapLast_f
+ =================
+ */
+ public static void WeapLast_f(edict_t ent) {
+ gclient_t cl;
+ int index;
+ gitem_t it;
+
+ cl = ent.client;
+
+ if (null == cl.pers.weapon || null == cl.pers.lastweapon)
+ return;
+
+ index = GameUtil.ITEM_INDEX(cl.pers.lastweapon);
+ if (0 == cl.pers.inventory[index])
+ return;
+ it = GameAI.itemlist[index];
+ if (null == it.use)
+ return;
+ if (0 == (it.flags & Defines.IT_WEAPON))
+ return;
+ it.use.use(ent, it);
+ }
+
+ /*
+ =================
+ Cmd_InvDrop_f
+ =================
+ */
+ public static void InvDrop_f(edict_t ent) {
+ gitem_t it;
+
+ GameAI.ValidateSelectedItem(ent);
+
+ if (ent.client.pers.selected_item == -1) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "No item to drop.\n");
+ return;
+ }
+
+ it = GameAI.itemlist[ent.client.pers.selected_item];
+ if (it.drop == null) {
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "Item is not dropable.\n");
+ return;
+ }
+ it.drop.drop(ent, it);
+ }
+
+ /*
+ ==================
+ Cmd_Score_f
+
+ Display the scoreboard
+ ==================
+ */
+ public static void Score_f(edict_t ent) {
+ ent.client.showinventory = false;
+ ent.client.showhelp = false;
+
+ if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value)
+ return;
+
+ if (ent.client.showscores) {
+ ent.client.showscores = false;
+ return;
+ }
+
+ ent.client.showscores = true;
+ GameAI.DeathmatchScoreboard(ent);
+ }
+
+ /*
+ ==================
+ Cmd_Help_f
+
+ Display the current help message
+ ==================
+ */
+ public static void Help_f(edict_t ent) {
+ // this is for backwards compatability
+ if (GameBase.deathmatch.value != 0) {
+ Score_f(ent);
+ return;
+ }
+
+ ent.client.showinventory = false;
+ ent.client.showscores = false;
+
+ if (ent.client.showhelp && (ent.client.pers.game_helpchanged == GameBase.game.helpchanged)) {
+ ent.client.showhelp = false;
+ return;
+ }
+
+ ent.client.showhelp = true;
+ ent.client.pers.helpchanged = 0;
+ GameAI.HelpComputer(ent);
+ }
+
+ //=======================================================================
+
+ /*
+ =================
+ Cmd_Kill_f
+ =================
+ */
+ public static void Kill_f(edict_t ent) {
+ if ((GameBase.level.time - ent.client.respawn_time) < 5)
+ return;
+ ent.flags &= ~Defines.FL_GODMODE;
+ ent.health = 0;
+ GameBase.meansOfDeath = Defines.MOD_SUICIDE;
+ GameAI.player_die.die(ent, ent, ent, 100000, GameBase.vec3_origin);
+ }
+
+ /*
+ =================
+ Cmd_PutAway_f
+ =================
+ */
+ public static void PutAway_f(edict_t ent) {
+ ent.client.showscores = false;
+ ent.client.showhelp = false;
+ ent.client.showinventory = false;
+
+ }
+
+ /*
+ =================
+ Cmd_Players_f
+ =================
+ */
+ public static void Players_f(edict_t ent) {
+ int i;
+ int count;
+ String small;
+ String large;
+
+ Integer index[] = new Integer[256];
+
+ count = 0;
+ for (i = 0; i < GameBase.maxclients.value; i++) {
+ if (GameBase.game.clients[i].pers.connected) {
+ index[count] = new Integer(i);
+ count++;
+ }
+ }
+
+ // sort by frags
+ //qsort(index, count, sizeof(index[0]), PlayerSort);
+ //replaced by:
+ Arrays.sort(index, 0, count - 1, GameAI.PlayerSort);
+
+ // print information
+ large = "";
+
+ for (i = 0; i < count; i++) {
+ small =
+ GameBase.game.clients[index[i].intValue()].ps.stats[Defines.STAT_FRAGS]
+ + " "
+ + GameBase.game.clients[index[i].intValue()].pers.netname
+ + "\n";
+
+ if (Lib.strlen(small) + Lib.strlen(large) > 1024 - 100) {
+ // can't print all of them in one packet
+ large += "...\n";
+ break;
+ }
+ large += small;
+ }
+
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "" + large + "\n" + count + " players\n");
+ }
+
+ /*
+ =================
+ Cmd_Wave_f
+ =================
+ */
+ public static void Wave_f(edict_t ent) {
+ int i;
+
+ i = Lib.atoi(GameBase.gi.argv(1));
+
+ // can't wave when ducked
+ if ((ent.client.ps.pmove.pm_flags & Defines.PMF_DUCKED) != 0)
+ return;
+
+ if (ent.client.anim_priority > Defines.ANIM_WAVE)
+ return;
+
+ ent.client.anim_priority = Defines.ANIM_WAVE;
+
+ switch (i) {
+ case 0 :
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "flipoff\n");
+ ent.s.frame = M_Player.FRAME_flip01 - 1;
+ ent.client.anim_end = M_Player.FRAME_flip12;
+ break;
+ case 1 :
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "salute\n");
+ ent.s.frame = M_Player.FRAME_salute01 - 1;
+ ent.client.anim_end = M_Player.FRAME_salute11;
+ break;
+ case 2 :
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "taunt\n");
+ ent.s.frame = M_Player.FRAME_taunt01 - 1;
+ ent.client.anim_end = M_Player.FRAME_taunt17;
+ break;
+ case 3 :
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "wave\n");
+ ent.s.frame = M_Player.FRAME_wave01 - 1;
+ ent.client.anim_end = M_Player.FRAME_wave11;
+ break;
+ case 4 :
+ default :
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "point\n");
+ ent.s.frame = M_Player.FRAME_point01 - 1;
+ ent.client.anim_end = M_Player.FRAME_point12;
+ break;
+ }
+ }
+
+ /*
+ ==================
+ Cmd_Say_f
+ ==================
+ */
+ public static void Say_f(edict_t ent, boolean team, boolean arg0) {
+
+ int i, j;
+ edict_t other;
+ char p;
+ String text;
+ gclient_t cl;
+
+ if (gi.argc() < 2 && !arg0)
+ return;
+
+ if (0 == ((int) (dmflags.value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
+ team = false;
+
+ if (team)
+ text = "(" + ent.client.pers.netname + "): ";
+ else
+ text = "" + ent.client.pers.netname + ": ";
+
+ if (arg0) {
+ strcat(text, gi.argv(0));
+ strcat(text, " ");
+ strcat(text, gi.args());
+ }
+ else {
+ if (gi.args().startsWith("\""))
+ text += gi.args().substring(1, gi.args().length() - 1);
+ else
+ text += gi.args();
+ /*
+ p = gi.args();
+ // *p ==
+ if (p == '"')
+ {
+ p++;
+ p[strlen(p) - 1] = 0;
+ }
+ strcat(text, p);
+ */
+ }
+
+ // don't let text be too long for malicious reasons
+ if (strlen(text) > 150)
+ //text[150] = 0;
+ text = text.substring(0, 150);
+
+ strcat(text, "\n");
+
+ if (flood_msgs.value != 0) {
+ cl = ent.client;
+
+ if (level.time < cl.flood_locktill) {
+ gi.cprintf(ent, PRINT_HIGH, "You can't talk for " + (int) (cl.flood_locktill - level.time) + " more seconds\n");
+ return;
+ }
+ i = (int) (cl.flood_whenhead - flood_msgs.value + 1);
+ if (i < 0)
+ //i = (sizeof(cl.flood_when) / sizeof(cl.flood_when[0])) + i;
+ i = (10) + i;
+ if (cl.flood_when[i] != 0 && level.time - cl.flood_when[i] < flood_persecond.value) {
+ cl.flood_locktill = level.time + flood_waitdelay.value;
+ gi.cprintf(ent, PRINT_CHAT, "Flood protection: You can't talk for " + (int) flood_waitdelay.value + " seconds.\n");
+ return;
+ }
+ //cl.flood_whenhead = (cl.flood_whenhead + 1) % (sizeof(cl.flood_when) / sizeof(cl.flood_when[0]));
+ cl.flood_whenhead = (cl.flood_whenhead + 1) % 10;
+ cl.flood_when[cl.flood_whenhead] = level.time;
+ }
+
+ if (dedicated.value != 0)
+ gi.cprintf(null, PRINT_CHAT, "" + text + "");
+
+ for (j = 1; j <= game.maxclients; j++) {
+ other = g_edicts[j];
+ if (!other.inuse)
+ continue;
+ if (other.client == null)
+ continue;
+ if (team) {
+ if (!OnSameTeam(ent, other))
+ continue;
+ }
+ gi.cprintf(other, PRINT_CHAT, "" + text + "");
+ }
+
+ }
+
+ /**
+ * Returns the playerlist.
+ * TODO: The list is badly formatted at the moment, RST.
+ */
+ public static void PlayerList_f(edict_t ent) {
+ int i;
+ String st;
+ String text;
+ edict_t e2;
+
+ // connect time, ping, score, name
+ text = "";
+
+ for (i = 0; i < GameBase.maxclients.value; i++) {
+ e2 = GameBase.g_edicts[1 + i];
+ if (!e2.inuse)
+ continue;
+
+ st =
+ ""
+ + (GameBase.level.framenum - e2.client.resp.enterframe) / 600
+ + ":"
+ + ((GameBase.level.framenum - e2.client.resp.enterframe) % 600) / 10
+ + " "
+ + e2.client.ping
+ + " "
+ + e2.client.resp.score
+ + " "
+ + e2.client.pers.netname
+ + " "
+ + (e2.client.resp.spectator ? " (spectator)" : "")
+ + "\n";
+
+ if (Lib.strlen(text) + Lib.strlen(st) > 1024 - 50) {
+ text += "And more...\n";
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, "" + text + "");
+ return;
+ }
+ text += st;
+ }
+ GameBase.gi.cprintf(ent, Defines.PRINT_HIGH, text);
+ }
+
+ // ======================================================================
+
+ /*
+ ===================
+ Cmd_ForwardToServer
+
+ adds the current command line as a clc_stringcmd to the client message.
+ things like godmode, noclip, etc, are commands directed to the server,
+ so when they are typed in at the console, they will need to be forwarded.
+ ===================
+ */
+ public static void ForwardToServer() {
+ String cmd;
+
+ cmd = Cmd.Argv(0);
+ if (Globals.cls.state <= Defines.ca_connected || cmd.charAt(0) == '-' || cmd.charAt(0) == '+') {
+ Com.Printf("Unknown command \"" + cmd + "\"\n");
+ return;
+ }
+
+ MSG.WriteByte(Globals.cls.netchan.message, Defines.clc_stringcmd);
+ SZ.Print(Globals.cls.netchan.message, cmd);
+ if (Cmd.Argc() > 1) {
+ SZ.Print(Globals.cls.netchan.message, " ");
+ SZ.Print(Globals.cls.netchan.message, Cmd.Args());
+ }
+ };
+
+}
diff --git a/src/jake2/game/EdictFindFilter.java b/src/jake2/game/EdictFindFilter.java
new file mode 100644
index 0000000..53fd1de
--- /dev/null
+++ b/src/jake2/game/EdictFindFilter.java
@@ -0,0 +1,32 @@
+/*
+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 07.11.2003 by RST.
+// $Id: EdictFindFilter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+/** Helps for filtering the iteration over the gedicts[] array, see GFind(). RST.*/
+
+public class EdictFindFilter {
+ boolean matches(edict_t e, String s) {
+ return false;
+ };
+} \ No newline at end of file
diff --git a/src/jake2/game/EdictIterator.java b/src/jake2/game/EdictIterator.java
new file mode 100644
index 0000000..ea0d5ca
--- /dev/null
+++ b/src/jake2/game/EdictIterator.java
@@ -0,0 +1,36 @@
+/*
+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 07.11.2003 by RST.
+// $Id: EdictIterator.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+/** Helps for iterating over the gedicts[] array. RST.*/
+
+class EdictIterator {
+
+ EdictIterator(int i) {
+ this.i= i;
+ }
+
+ edict_t o;
+ int i;
+} \ No newline at end of file
diff --git a/src/jake2/game/EndianHandler.java b/src/jake2/game/EndianHandler.java
new file mode 100644
index 0000000..510541d
--- /dev/null
+++ b/src/jake2/game/EndianHandler.java
@@ -0,0 +1,77 @@
+/*
+ * AbstractEndianHandler.java
+ * Copyright (C) 2003
+ *
+ * $Id: EndianHandler.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.game;
+
+
+/**
+ * AbstractEndianHandler</code>
+ */
+public abstract class EndianHandler{
+
+ private static final int mask = 0xFF;
+
+ abstract public float BigFloat(float f);
+ abstract public short BigShort(short s);
+ abstract public int BigLong(int i);
+ abstract public float LittleFloat(float f);
+ abstract public short LittleShort(short s);
+ abstract public int LittleLong(int i);
+
+ public static float swapFloat(float f) {
+ int i = Float.floatToRawIntBits(f);
+ i = swapInt(i);
+ f = Float.intBitsToFloat(i);
+
+ return f;
+ }
+
+ public static int swapInt(int i) {
+
+ int a = i & mask;
+ i >>>= 8;
+
+ a <<= 24;
+
+ int b = i & mask;
+
+ i >>>= 8;
+ b <<= 16;
+
+ int c = i & mask;
+ i >>>= 8;
+ c <<= 8;
+
+ return i | c | b | a;
+ }
+
+ public static short swapShort(short s) {
+ int a = s & mask;
+ a <<= 8;
+ int b = (s >>> 8) & mask;
+
+ return (short)(b | a);
+ }
+}
diff --git a/src/jake2/game/EntBlockedAdapter.java b/src/jake2/game/EntBlockedAdapter.java
new file mode 100644
index 0000000..8ed731f
--- /dev/null
+++ b/src/jake2/game/EntBlockedAdapter.java
@@ -0,0 +1,30 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntBlockedAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class EntBlockedAdapter extends SuperAdapter{
+ // move to moveinfo?
+ public void blocked(edict_t self, edict_t other) {
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/EntDieAdapter.java b/src/jake2/game/EntDieAdapter.java
new file mode 100644
index 0000000..3900bd4
--- /dev/null
+++ b/src/jake2/game/EntDieAdapter.java
@@ -0,0 +1,29 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntDieAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class EntDieAdapter extends SuperAdapter {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/EntDodgeAdapter.java b/src/jake2/game/EntDodgeAdapter.java
new file mode 100644
index 0000000..17e8004
--- /dev/null
+++ b/src/jake2/game/EntDodgeAdapter.java
@@ -0,0 +1,29 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntDodgeAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class EntDodgeAdapter extends SuperAdapter {
+ public void dodge(edict_t self, edict_t other, float eta) {
+ }
+}
diff --git a/src/jake2/game/EntInteractAdapter.java b/src/jake2/game/EntInteractAdapter.java
new file mode 100644
index 0000000..d65e16e
--- /dev/null
+++ b/src/jake2/game/EntInteractAdapter.java
@@ -0,0 +1,31 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntInteractAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class EntInteractAdapter extends SuperAdapter {
+ public boolean interact(edict_t self, edict_t other) {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/EntPainAdapter.java b/src/jake2/game/EntPainAdapter.java
new file mode 100644
index 0000000..129876b
--- /dev/null
+++ b/src/jake2/game/EntPainAdapter.java
@@ -0,0 +1,29 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntPainAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class EntPainAdapter extends SuperAdapter {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/EntThinkAdapter.java b/src/jake2/game/EntThinkAdapter.java
new file mode 100644
index 0000000..4bf7ef8
--- /dev/null
+++ b/src/jake2/game/EntThinkAdapter.java
@@ -0,0 +1,31 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntThinkAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public abstract class EntThinkAdapter extends SuperAdapter {
+
+ public boolean think(edict_t self) {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/EntTouchAdapter.java b/src/jake2/game/EntTouchAdapter.java
new file mode 100644
index 0000000..732e1fa
--- /dev/null
+++ b/src/jake2/game/EntTouchAdapter.java
@@ -0,0 +1,30 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntTouchAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class EntTouchAdapter extends SuperAdapter {
+
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/EntUseAdapter.java b/src/jake2/game/EntUseAdapter.java
new file mode 100644
index 0000000..03bc62b
--- /dev/null
+++ b/src/jake2/game/EntUseAdapter.java
@@ -0,0 +1,30 @@
+/*
+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 08.11.2003 by RST.
+// $Id: EntUseAdapter.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+public class EntUseAdapter extends SuperAdapter {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/Fire.java b/src/jake2/game/Fire.java
new file mode 100644
index 0000000..9a68b08
--- /dev/null
+++ b/src/jake2/game/Fire.java
@@ -0,0 +1,584 @@
+/*
+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 04.12.2003 by RST.
+// $Id: Fire.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+
+ import jake2.*;
+ import jake2.client.*;
+ import jake2.qcommon.*;
+ import jake2.render.*;
+ import jake2.server.*;
+import jake2.util.*;
+
+public class Fire {
+
+ /*
+ =================
+ fire_hit
+
+ Used for all impact (hit/punch/slash) attacks
+ =================
+ */
+ public static boolean fire_hit(edict_t self, float[] aim, int damage, int kick) {
+ trace_t tr;
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, up= { 0, 0, 0 };
+ float[] v= { 0, 0, 0 };
+ float[] point= { 0, 0, 0 };
+ float range;
+ float[] dir= { 0, 0, 0 };
+
+ //see if enemy is in range
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, dir);
+ range= Math3D.VectorLength(dir);
+ if (range > aim[0])
+ return false;
+
+ if (aim[1] > self.mins[0] && aim[1] < self.maxs[0]) {
+ // the hit is straight on so back the range up to the edge of their bbox
+ range -= self.enemy.maxs[0];
+ } else {
+ // this is a side hit so adjust the "right" value out to the edge of their bbox
+ if (aim[1] < 0)
+ aim[1]= self.enemy.mins[0];
+ else
+ aim[1]= self.enemy.maxs[0];
+ }
+
+ Math3D.VectorMA(self.s.origin, range, dir, point);
+
+ tr= GameBase.gi.trace(self.s.origin, null, null, point, self, Defines.MASK_SHOT);
+ if (tr.fraction < 1) {
+ if (0 == tr.ent.takedamage)
+ return false;
+ // if it will hit any client/monster then hit the one we wanted to hit
+ if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0 || (tr.ent.client != null))
+ tr.ent= self.enemy;
+ }
+
+ Math3D.AngleVectors(self.s.angles, forward, right, up);
+ Math3D.VectorMA(self.s.origin, range, forward, point);
+ Math3D.VectorMA(point, aim[1], right, point);
+ Math3D.VectorMA(point, aim[2], up, point);
+ Math3D.VectorSubtract(point, self.enemy.s.origin, dir);
+
+ // do the damage
+ GameUtil.T_Damage(
+ tr.ent,
+ self,
+ self,
+ dir,
+ point,
+ GameBase.vec3_origin,
+ damage,
+ kick / 2,
+ Defines.DAMAGE_NO_KNOCKBACK,
+ Defines.MOD_HIT);
+
+ if (0 == (tr.ent.svflags & Defines.SVF_MONSTER) && (null == tr.ent.client))
+ return false;
+
+ // do our special form of knockback here
+ Math3D.VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, v);
+ Math3D.VectorSubtract(v, point, v);
+ Math3D.VectorNormalize(v);
+ Math3D.VectorMA(self.enemy.velocity, kick, v, self.enemy.velocity);
+ if (self.enemy.velocity[2] > 0)
+ self.enemy.groundentity= null;
+ return true;
+ }
+ /*
+ =================
+ fire_lead
+
+ This is an internal support routine used for bullet/pellet based weapons.
+ =================
+ */
+ public static void fire_lead(
+ edict_t self,
+ float[] start,
+ float[] aimdir,
+ int damage,
+ int kick,
+ int te_impact,
+ int hspread,
+ int vspread,
+ int mod) {
+ trace_t tr;
+ float[] dir= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, up= { 0, 0, 0 };
+ float[] end= { 0, 0, 0 };
+ float r;
+ float u;
+ float[] water_start= { 0, 0, 0 };
+ boolean water= false;
+ int content_mask= Defines.MASK_SHOT | Defines.MASK_WATER;
+
+ tr= GameBase.gi.trace(self.s.origin, null, null, start, self, Defines.MASK_SHOT);
+ if (!(tr.fraction < 1.0)) {
+ Math3D.vectoangles(aimdir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+
+ r= Lib.crandom() * hspread;
+ u= Lib.crandom() * vspread;
+ Math3D.VectorMA(start, 8192, forward, end);
+ Math3D.VectorMA(end, r, right, end);
+ Math3D.VectorMA(end, u, up, end);
+
+ if ((GameBase.gi.pointcontents.pointcontents(start) & Defines.MASK_WATER) != 0) {
+ water= true;
+ Math3D.VectorCopy(start, water_start);
+ content_mask &= ~Defines.MASK_WATER;
+ }
+
+ tr= GameBase.gi.trace(start, null, null, end, self, content_mask);
+
+ // see if we hit water
+ if ((tr.contents & Defines.MASK_WATER) != 0) {
+ int color;
+
+ water= true;
+ Math3D.VectorCopy(tr.endpos, water_start);
+
+ if (0 == Math3D.VectorCompare(start, tr.endpos)) {
+ if ((tr.contents & Defines.CONTENTS_WATER) != 0) {
+ if (Lib.strcmp(tr.surface.name, "*brwater") == 0)
+ color= Defines.SPLASH_BROWN_WATER;
+ else
+ color= Defines.SPLASH_BLUE_WATER;
+ } else if ((tr.contents & Defines.CONTENTS_SLIME) != 0)
+ color= Defines.SPLASH_SLIME;
+ else if ((tr.contents & Defines.CONTENTS_LAVA) != 0)
+ color= Defines.SPLASH_LAVA;
+ else
+ color= Defines.SPLASH_UNKNOWN;
+
+ if (color != Defines.SPLASH_UNKNOWN) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_SPLASH);
+ GameBase.gi.WriteByte(8);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.WriteDir(tr.plane.normal);
+ GameBase.gi.WriteByte(color);
+ GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
+ }
+
+ // change bullet's course when it enters water
+ Math3D.VectorSubtract(end, start, dir);
+ Math3D.vectoangles(dir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+ r= Lib.crandom() * hspread * 2;
+ u= Lib.crandom() * vspread * 2;
+ Math3D.VectorMA(water_start, 8192, forward, end);
+ Math3D.VectorMA(end, r, right, end);
+ Math3D.VectorMA(end, u, up, end);
+ }
+
+ // re-trace ignoring water this time
+ tr= GameBase.gi.trace(water_start, null, null, end, self, Defines.MASK_SHOT);
+ }
+ }
+
+ // send gun puff / flash
+ if (!((tr.surface != null) && 0 != (tr.surface.flags & Defines.SURF_SKY))) {
+ if (tr.fraction < 1.0) {
+ if (tr.ent.takedamage != 0) {
+ GameUtil.T_Damage(
+ tr.ent,
+ self,
+ self,
+ aimdir,
+ tr.endpos,
+ tr.plane.normal,
+ damage,
+ kick,
+ Defines.DAMAGE_BULLET,
+ mod);
+ } else {
+ if (!"sky".equals(tr.surface.name)) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(te_impact);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.WriteDir(tr.plane.normal);
+ GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PVS);
+
+ if (self.client != null)
+ GameWeapon.PlayerNoise(self, tr.endpos, Defines.PNOISE_IMPACT);
+ }
+ }
+ }
+ }
+
+ // if went through water, determine where the end and make a bubble trail
+ if (water) {
+ float[] pos= { 0, 0, 0 };
+
+ Math3D.VectorSubtract(tr.endpos, water_start, dir);
+ Math3D.VectorNormalize(dir);
+ Math3D.VectorMA(tr.endpos, -2, dir, pos);
+ if ((Game.gi.pointcontents.pointcontents(pos) & Defines.MASK_WATER) != 0)
+ Math3D.VectorCopy(pos, tr.endpos);
+ else
+ tr= GameBase.gi.trace(pos, null, null, water_start, tr.ent, Defines.MASK_WATER);
+
+ Math3D.VectorAdd(water_start, tr.endpos, pos);
+ Math3D.VectorScale(pos, 0.5f, pos);
+
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_BUBBLETRAIL);
+ GameBase.gi.WritePosition(water_start);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.multicast(pos, Defines.MULTICAST_PVS);
+ }
+ }
+ /*
+ =================
+ fire_bullet
+
+ Fires a single round. Used for machinegun and chaingun. Would be fine for
+ pistols, rifles, etc....
+ =================
+ */
+ public static void fire_bullet(
+ edict_t self,
+ float[] start,
+ float[] aimdir,
+ int damage,
+ int kick,
+ int hspread,
+ int vspread,
+ int mod) {
+ fire_lead(self, start, aimdir, damage, kick, Defines.TE_GUNSHOT, hspread, vspread, mod);
+ }
+ /*
+ =================
+ fire_shotgun
+
+ Shoots shotgun pellets. Used by shotgun and super shotgun.
+ =================
+ */
+ public static void fire_shotgun(
+ edict_t self,
+ float[] start,
+ float[] aimdir,
+ int damage,
+ int kick,
+ int hspread,
+ int vspread,
+ int count,
+ int mod) {
+ int i;
+
+ for (i= 0; i < count; i++)
+ fire_lead(self, start, aimdir, damage, kick, Defines.TE_SHOTGUN, hspread, vspread, mod);
+ }
+ public static void fire_blaster(
+ edict_t self,
+ float[] start,
+ float[] dir,
+ int damage,
+ int speed,
+ int effect,
+ boolean hyper) {
+ edict_t bolt;
+ trace_t tr;
+
+ Math3D.VectorNormalize(dir);
+
+ bolt= GameUtil.G_Spawn();
+ bolt.svflags= Defines.SVF_DEADMONSTER;
+ // yes, I know it looks weird that projectiles are deadmonsters
+ // what this means is that when prediction is used against the object
+ // (blaster/hyperblaster shots), the player won't be solid clipped against
+ // the object. Right now trying to run into a firing hyperblaster
+ // is very jerky since you are predicted 'against' the shots.
+ Math3D.VectorCopy(start, bolt.s.origin);
+ Math3D.VectorCopy(start, bolt.s.old_origin);
+ Math3D.vectoangles(dir, bolt.s.angles);
+ Math3D.VectorScale(dir, speed, bolt.velocity);
+ bolt.movetype= Defines.MOVETYPE_FLYMISSILE;
+ bolt.clipmask= Defines.MASK_SHOT;
+ bolt.solid= Defines.SOLID_BBOX;
+ bolt.s.effects |= effect;
+ Math3D.VectorClear(bolt.mins);
+ Math3D.VectorClear(bolt.maxs);
+ bolt.s.modelindex= GameBase.gi.modelindex("models/objects/laser/tris.md2");
+ bolt.s.sound= GameBase.gi.soundindex("misc/lasfly.wav");
+ bolt.owner= self;
+ bolt.touch= GameWeapon.blaster_touch;
+ bolt.nextthink= GameBase.level.time + 2;
+ bolt.think= GameUtil.G_FreeEdictA;
+ bolt.dmg= damage;
+ bolt.classname= "bolt";
+ if (hyper)
+ bolt.spawnflags= 1;
+ GameBase.gi.linkentity(bolt);
+
+ if (self.client != null)
+ GameWeapon.check_dodge(self, bolt.s.origin, dir, speed);
+
+ tr= GameBase.gi.trace(self.s.origin, null, null, bolt.s.origin, bolt, Defines.MASK_SHOT);
+ if (tr.fraction < 1.0) {
+ Math3D.VectorMA(bolt.s.origin, -10, dir, bolt.s.origin);
+ bolt.touch.touch(bolt, tr.ent, null, null);
+ }
+ }
+ /*
+ =================
+ fire_grenade
+ =================
+ */
+
+ public static void fire_grenade(
+ edict_t self,
+ float[] start,
+ float[] aimdir,
+ int damage,
+ int speed,
+ float timer,
+ float damage_radius) {
+ edict_t grenade;
+ float[] dir= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, up= { 0, 0, 0 };
+
+ Math3D.vectoangles(aimdir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+
+ grenade= GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, grenade.s.origin);
+ Math3D.VectorScale(aimdir, speed, grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up, grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right, grenade.velocity);
+ Math3D.VectorSet(grenade.avelocity, 300, 300, 300);
+ grenade.movetype= Defines.MOVETYPE_BOUNCE;
+ grenade.clipmask= Defines.MASK_SHOT;
+ grenade.solid= Defines.SOLID_BBOX;
+ grenade.s.effects |= Defines.EF_GRENADE;
+ Math3D.VectorClear(grenade.mins);
+ Math3D.VectorClear(grenade.maxs);
+ grenade.s.modelindex= GameBase.gi.modelindex("models/objects/grenade/tris.md2");
+ grenade.owner= self;
+ grenade.touch= GameWeapon.Grenade_Touch;
+ grenade.nextthink= GameBase.level.time + timer;
+ grenade.think= GameWeapon.Grenade_Explode;
+ grenade.dmg= damage;
+ grenade.dmg_radius= damage_radius;
+ grenade.classname= "grenade";
+
+ GameBase.gi.linkentity(grenade);
+ }
+ public static void fire_grenade2(
+ edict_t self,
+ float[] start,
+ float[] aimdir,
+ int damage,
+ int speed,
+ float timer,
+ float damage_radius,
+ boolean held) {
+ edict_t grenade;
+ float[] dir= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, up= { 0, 0, 0 };
+
+ Math3D.vectoangles(aimdir, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+
+ grenade= GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, grenade.s.origin);
+ Math3D.VectorScale(aimdir, speed, grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, 200f + Lib.crandom() * 10.0f, up, grenade.velocity);
+ Math3D.VectorMA(grenade.velocity, Lib.crandom() * 10.0f, right, grenade.velocity);
+ Math3D.VectorSet(grenade.avelocity, 300f, 300f, 300f);
+ grenade.movetype= Defines.MOVETYPE_BOUNCE;
+ grenade.clipmask= Defines.MASK_SHOT;
+ grenade.solid= Defines.SOLID_BBOX;
+ grenade.s.effects |= Defines.EF_GRENADE;
+ Math3D.VectorClear(grenade.mins);
+ Math3D.VectorClear(grenade.maxs);
+ grenade.s.modelindex= GameBase.gi.modelindex("models/objects/grenade2/tris.md2");
+ grenade.owner= self;
+ grenade.touch= GameWeapon.Grenade_Touch;
+ grenade.nextthink= GameBase.level.time + timer;
+ grenade.think= GameWeapon.Grenade_Explode;
+ grenade.dmg= damage;
+ grenade.dmg_radius= damage_radius;
+ grenade.classname= "hgrenade";
+ if (held)
+ grenade.spawnflags= 3;
+ else
+ grenade.spawnflags= 1;
+ grenade.s.sound= GameBase.gi.soundindex("weapons/hgrenc1b.wav");
+
+ if (timer <= 0.0)
+ GameWeapon.Grenade_Explode.think(grenade);
+ else {
+ GameBase.gi.sound(self, Defines.CHAN_WEAPON, GameBase.gi.soundindex("weapons/hgrent1a.wav"), 1, Defines.ATTN_NORM, 0);
+ GameBase.gi.linkentity(grenade);
+ }
+ }
+ public static void fire_rocket(
+ edict_t self,
+ float[] start,
+ float[] dir,
+ int damage,
+ int speed,
+ float damage_radius,
+ int radius_damage) {
+ edict_t rocket;
+
+ rocket= GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, rocket.s.origin);
+ Math3D.VectorCopy(dir, rocket.movedir);
+ Math3D.vectoangles(dir, rocket.s.angles);
+ Math3D.VectorScale(dir, speed, rocket.velocity);
+ rocket.movetype= Defines.MOVETYPE_FLYMISSILE;
+ rocket.clipmask= Defines.MASK_SHOT;
+ rocket.solid= Defines.SOLID_BBOX;
+ rocket.s.effects |= Defines.EF_ROCKET;
+ Math3D.VectorClear(rocket.mins);
+ Math3D.VectorClear(rocket.maxs);
+ rocket.s.modelindex= GameBase.gi.modelindex("models/objects/rocket/tris.md2");
+ rocket.owner= self;
+ rocket.touch= GameWeapon.rocket_touch;
+ rocket.nextthink= GameBase.level.time + 8000 / speed;
+ rocket.think= GameUtil.G_FreeEdictA;
+ rocket.dmg= damage;
+ rocket.radius_dmg= radius_damage;
+ rocket.dmg_radius= damage_radius;
+ rocket.s.sound= GameBase.gi.soundindex("weapons/rockfly.wav");
+ rocket.classname= "rocket";
+
+ if (self.client != null)
+ GameWeapon.check_dodge(self, rocket.s.origin, dir, speed);
+
+ GameBase.gi.linkentity(rocket);
+ }
+ /*
+ =================
+ fire_rail
+ =================
+ */
+ public static void fire_rail(edict_t self, float[] start, float[] aimdir, int damage, int kick) {
+ float[] from= { 0, 0, 0 };
+ float[] end= { 0, 0, 0 };
+ trace_t tr= null;
+ edict_t ignore;
+ int mask;
+ boolean water;
+
+ Math3D.VectorMA(start, 8192f, aimdir, end);
+ Math3D.VectorCopy(start, from);
+ ignore= self;
+ water= false;
+ mask= Defines.MASK_SHOT | Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA;
+ while (ignore != null) {
+ tr= GameBase.gi.trace(from, null, null, end, ignore, mask);
+
+ if ((tr.contents & (Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA)) != 0) {
+ mask &= ~(Defines.CONTENTS_SLIME | Defines.CONTENTS_LAVA);
+ water= true;
+ } else {
+ //ZOID--added so rail goes through SOLID_BBOX entities (gibs, etc)
+ if ((tr.ent.svflags & Defines.SVF_MONSTER) != 0
+ || (tr.ent.client != null)
+ || (tr.ent.solid == Defines.SOLID_BBOX))
+ ignore= tr.ent;
+ else
+ ignore= null;
+
+ if ((tr.ent != self) && (tr.ent.takedamage != 0))
+ GameUtil.T_Damage(
+ tr.ent,
+ self,
+ self,
+ aimdir,
+ tr.endpos,
+ tr.plane.normal,
+ damage,
+ kick,
+ 0,
+ Defines.MOD_RAILGUN);
+ }
+
+ Math3D.VectorCopy(tr.endpos, from);
+ }
+
+ // send gun puff / flash
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
+ GameBase.gi.WritePosition(start);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.multicast(self.s.origin, Defines.MULTICAST_PHS);
+ // gi.multicast (start, MULTICAST_PHS);
+ if (water) {
+ GameBase.gi.WriteByte(Defines.svc_temp_entity);
+ GameBase.gi.WriteByte(Defines.TE_RAILTRAIL);
+ GameBase.gi.WritePosition(start);
+ GameBase.gi.WritePosition(tr.endpos);
+ GameBase.gi.multicast(tr.endpos, Defines.MULTICAST_PHS);
+ }
+
+ if (self.client != null)
+ GameWeapon.PlayerNoise(self, tr.endpos, Defines.PNOISE_IMPACT);
+ }
+ public static void fire_bfg(
+ edict_t self,
+ float[] start,
+ float[] dir,
+ int damage,
+ int speed,
+ float damage_radius) {
+ edict_t bfg;
+
+ bfg= GameUtil.G_Spawn();
+ Math3D.VectorCopy(start, bfg.s.origin);
+ Math3D.VectorCopy(dir, bfg.movedir);
+ Math3D.vectoangles(dir, bfg.s.angles);
+ Math3D.VectorScale(dir, speed, bfg.velocity);
+ bfg.movetype= Defines.MOVETYPE_FLYMISSILE;
+ bfg.clipmask= Defines.MASK_SHOT;
+ bfg.solid= Defines.SOLID_BBOX;
+ bfg.s.effects |= Defines.EF_BFG | Defines.EF_ANIM_ALLFAST;
+ Math3D.VectorClear(bfg.mins);
+ Math3D.VectorClear(bfg.maxs);
+ bfg.s.modelindex= GameBase.gi.modelindex("sprites/s_bfg1.sp2");
+ bfg.owner= self;
+ bfg.touch= GameWeapon.bfg_touch;
+ bfg.nextthink= GameBase.level.time + 8000 / speed;
+ bfg.think= GameUtil.G_FreeEdictA;
+ bfg.radius_dmg= damage;
+ bfg.dmg_radius= damage_radius;
+ bfg.classname= "bfg blast";
+ bfg.s.sound= GameBase.gi.soundindex("weapons/bfg__l1a.wav");
+
+ bfg.think= GameWeapon.bfg_think;
+ bfg.nextthink= GameBase.level.time + Defines.FRAMETIME;
+ bfg.teammaster= bfg;
+ bfg.teamchain= null;
+
+ if (self.client != null)
+ GameWeapon.check_dodge(self, bfg.s.origin, dir, speed);
+
+ GameBase.gi.linkentity(bfg);
+ }
+}
diff --git a/src/jake2/game/Game.java b/src/jake2/game/Game.java
new file mode 100644
index 0000000..1a98896
--- /dev/null
+++ b/src/jake2/game/Game.java
@@ -0,0 +1,29 @@
+/*
+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 17.11.2003 by RST.
+// $Id: Game.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.game;
+
+// just offers the game namespace. will grow more.
+
+public class Game extends GameSVCmds{
+}
diff --git a/src/jake2/game/GameAI.java b/src/jake2/game/GameAI.java
new file mode 100644
index 0000000..2e32ed8
--- /dev/null
+++ b/src/jake2/game/GameAI.java
@@ -0,0 +1,3520 @@
+/*
+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 02.11.2003 by RST.
+// $Id: GameAI.java,v 1.1 2004-07-07 19:58:55 hzi Exp $
+
+package jake2.game;
+
+import jake2.Defines;
+import jake2.client.M;
+import jake2.util.*;
+
+import java.util.*;
+
+public class GameAI extends M_Flash {
+
+ /*
+ ===============
+ GetItemByIndex
+ ===============
+ */
+ public static gitem_t GetItemByIndex(int index) {
+
+ if (index == 0 || index >= game.num_items)
+ return null;
+
+ return itemlist[index];
+ }
+
+
+ /** Common Boss explode animation.*/
+
+ public static EntThinkAdapter BossExplode = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] org = { 0, 0, 0 };
+
+ int n;
+
+ self.think = BossExplode;
+ Math3D.VectorCopy(self.s.origin, org);
+ org[2] += 24 + (Lib.rand() & 15);
+ switch (self.count++) {
+ case 0 :
+ org[0] -= 24;
+ org[1] -= 24;
+ break;
+ case 1 :
+ org[0] += 24;
+ org[1] += 24;
+ break;
+ case 2 :
+ org[0] += 24;
+ org[1] -= 24;
+ break;
+ case 3 :
+ org[0] -= 24;
+ org[1] += 24;
+ break;
+ case 4 :
+ org[0] -= 48;
+ org[1] -= 48;
+ break;
+ case 5 :
+ org[0] += 48;
+ org[1] += 48;
+ break;
+ case 6 :
+ org[0] -= 48;
+ org[1] += 48;
+ break;
+ case 7 :
+ org[0] += 48;
+ org[1] -= 48;
+ break;
+ case 8 :
+ self.s.sound = 0;
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", 500, GIB_ORGANIC);
+ for (n = 0; n < 8; n++)
+ ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", 500, GIB_METALLIC);
+ ThrowGib(self, "models/objects/gibs/chest/tris.md2", 500, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/gear/tris.md2", 500, GIB_METALLIC);
+ self.deadflag = DEAD_DEAD;
+ return true;
+ }
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_EXPLOSION1);
+ gi.WritePosition(org);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+
+ self.nextthink = level.time + 0.1f;
+ return true;
+ }
+ };
+
+ public static void AttackFinished(edict_t self, float time) {
+ self.monsterinfo.attack_finished = level.time + time;
+ }
+
+ public static EntThinkAdapter walkmonster_start_go = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if (0 == (self.spawnflags & 2) && level.time < 1) {
+ M.M_droptofloor.think(self);
+
+ if (self.groundentity != null)
+ if (!M.M_walkmove(self, 0, 0))
+ gi.dprintf(self.classname + " in solid at " + Lib.vtos(self.s.origin) + "\n");
+ }
+
+ if (0 == self.yaw_speed)
+ self.yaw_speed = 20;
+ self.viewheight = 25;
+
+ Monster.monster_start_go(self);
+
+ if ((self.spawnflags & 2) != 0)
+ Monster.monster_triggered_start.think(self);
+ return true;
+ }
+ };
+
+ public static EntThinkAdapter walkmonster_start = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.think = walkmonster_start_go;
+ Monster.monster_start(self);
+ return true;
+ }
+ };
+
+ public static EntThinkAdapter flymonster_start_go = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (!M.M_walkmove(self, 0, 0))
+ gi.dprintf(self.classname + " in solid at " + Lib.vtos(self.s.origin) + "\n");
+
+ if (0 == self.yaw_speed)
+ self.yaw_speed = 10;
+ self.viewheight = 25;
+
+ Monster.monster_start_go(self);
+
+ if ((self.spawnflags & 2) != 0)
+ Monster.monster_triggered_start.think(self);
+ return true;
+ }
+ };
+
+ public static EntThinkAdapter flymonster_start = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.flags |= FL_FLY;
+ self.think = flymonster_start_go;
+ Monster.monster_start(self);
+ return true;
+ }
+ };
+
+ public static EntThinkAdapter swimmonster_start_go = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (0 == self.yaw_speed)
+ self.yaw_speed = 10;
+ self.viewheight = 10;
+
+ Monster.monster_start_go(self);
+
+ if ((self.spawnflags & 2) != 0)
+ Monster.monster_triggered_start.think(self);
+ return true;
+ }
+ };
+
+ public static EntThinkAdapter swimmonster_start = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ {
+ self.flags |= FL_SWIM;
+ self.think = swimmonster_start_go;
+ Monster.monster_start(self);
+ return true;
+ }
+ }
+ };
+
+ /*
+ =============
+ ai_turn
+
+ don't move, but turn towards ideal_yaw
+ Distance is for slight position adjustments needed by the animations
+ =============
+ */
+ public static AIAdapter ai_turn = new AIAdapter() {
+ public void ai(edict_t self, float dist) {
+ if (dist != 0)
+ M.M_walkmove(self, self.s.angles[YAW], dist);
+
+ if (FindTarget(self))
+ return;
+
+ M.M_ChangeYaw(self);
+ }
+ };
+
+ /*
+ =============
+ ai_move
+
+ Move the specified distance at current facing.
+ This replaces the QC functions: ai_forward, ai_back, ai_pain, and ai_painforward
+ ==============
+ */
+ public static AIAdapter ai_move = new AIAdapter() {
+ public void ai(edict_t self, float dist) {
+ M.M_walkmove(self, self.s.angles[YAW], dist);
+ }
+ };
+
+ /*
+ =============
+ ai_walk
+
+ The monster is walking it's beat
+ =============
+ */
+ public static AIAdapter ai_walk = new AIAdapter() {
+ public void ai(edict_t self, float dist) {
+ M.M_MoveToGoal(self, dist);
+
+ // check for noticing a player
+ if (FindTarget(self))
+ return;
+
+ if ((self.monsterinfo.search != null) && (level.time > self.monsterinfo.idle_time)) {
+ if (self.monsterinfo.idle_time != 0) {
+ self.monsterinfo.search.think(self);
+ self.monsterinfo.idle_time = level.time + 15 + Lib.random() * 15;
+ }
+ else {
+ self.monsterinfo.idle_time = level.time + Lib.random() * 15;
+ }
+ }
+ }
+ };
+
+ /*
+ =============
+ ai_stand
+
+ Used for standing around and looking for players
+ Distance is for slight position adjustments needed by the animations
+ ==============
+ */
+
+ public static AIAdapter ai_stand = new AIAdapter() {
+ public void ai(edict_t self, float dist) {
+ float[] v = { 0, 0, 0 };
+
+ if (dist != 0)
+ M.M_walkmove(self, self.s.angles[YAW], dist);
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ if (self.enemy != null) {
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, v);
+ self.ideal_yaw = Math3D.vectoyaw(v);
+ if (self.s.angles[YAW] != self.ideal_yaw && 0 != (self.monsterinfo.aiflags & AI_TEMP_STAND_GROUND)) {
+ self.monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+ self.monsterinfo.run.think(self);
+ }
+ M.M_ChangeYaw(self);
+ ai_checkattack(self, 0);
+ }
+ else
+ FindTarget(self);
+ return;
+ }
+
+ if (FindTarget(self))
+ return;
+
+ if (level.time > self.monsterinfo.pausetime) {
+ self.monsterinfo.walk.think(self);
+ return;
+ }
+
+ if (0 == (self.spawnflags & 1) && (self.monsterinfo.idle != null) && (level.time > self.monsterinfo.idle_time)) {
+ if (self.monsterinfo.idle_time != 0) {
+ self.monsterinfo.idle.think(self);
+ self.monsterinfo.idle_time = level.time + 15 + Lib.random() * 15;
+ }
+ else {
+ self.monsterinfo.idle_time = level.time + Lib.random() * 15;
+ }
+ }
+ }
+ };
+
+ /*
+ =============
+ ai_charge
+
+ Turns towards target and advances
+ Use this call with a distnace of 0 to replace ai_face
+ ==============
+ */
+ public static AIAdapter ai_charge = new AIAdapter() {
+
+ public void ai(edict_t self, float dist) {
+ float[] v = { 0, 0, 0 };
+
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, v);
+ self.ideal_yaw = Math3D.vectoyaw(v);
+ M.M_ChangeYaw(self);
+
+ if (dist != 0)
+ M.M_walkmove(self, self.s.angles[YAW], dist);
+ }
+ };
+
+ /*
+ =============
+ ai_turn
+
+ don't move, but turn towards ideal_yaw
+ Distance is for slight position adjustments needed by the animations
+ =============
+ */
+ public static void ai_turn(edict_t self, float dist) {
+ if (dist != 0)
+ M.M_walkmove(self, self.s.angles[YAW], dist);
+
+ if (FindTarget(self))
+ return;
+
+ M.M_ChangeYaw(self);
+ }
+
+ /*
+
+ .enemy
+ Will be world if not currently angry at anyone.
+
+ .movetarget
+ The next path spot to walk toward. If .enemy, ignore .movetarget.
+ When an enemy is killed, the monster will try to return to it's path.
+
+ .hunt_time
+ Set to time + something when the player is in sight, but movement straight for
+ him is blocked. This causes the monster to use wall following code for
+ movement direction instead of sighting on the player.
+
+ .ideal_yaw
+ A yaw angle of the intended direction, which will be turned towards at up
+ to 45 deg / state. If the enemy is in view and hunt_time is not active,
+ this will be the exact line towards the enemy.
+
+ .pausetime
+ A monster will leave it's stand state and head towards it's .movetarget when
+ time > .pausetime.
+
+ walkmove(angle, speed) primitive is all or nothing
+ */
+
+ /*
+ ============
+ FacingIdeal
+
+ ============
+ */
+
+ public static boolean FacingIdeal(edict_t self) {
+ float delta;
+
+ delta = Math3D.anglemod(self.s.angles[YAW] - self.ideal_yaw);
+ if (delta > 45 && delta < 315)
+ return false;
+ return true;
+ }
+
+ /*
+ =============
+ ai_run_melee
+
+ Turn and close until within an angle to launch a melee attack
+ =============
+ */
+ public static void ai_run_melee(edict_t self) {
+ self.ideal_yaw = enemy_yaw;
+ M.M_ChangeYaw(self);
+
+ if (FacingIdeal(self)) {
+ self.monsterinfo.melee.think(self);
+ self.monsterinfo.attack_state = AS_STRAIGHT;
+ }
+ }
+
+ /*
+ =============
+ ai_run_missile
+
+ Turn in place until within an angle to launch a missile attack
+ =============
+ */
+ public static void ai_run_missile(edict_t self) {
+ self.ideal_yaw = enemy_yaw;
+ M.M_ChangeYaw(self);
+
+ if (FacingIdeal(self)) {
+ self.monsterinfo.attack.think(self);
+ self.monsterinfo.attack_state = AS_STRAIGHT;
+ }
+ };
+
+ /*
+ =============
+ ai_run_slide
+
+ Strafe sideways, but stay at aproximately the same range
+ =============
+ */
+ public static void ai_run_slide(edict_t self, float distance) {
+ float ofs;
+
+ self.ideal_yaw = enemy_yaw;
+ M.M_ChangeYaw(self);
+
+ if (self.monsterinfo.lefty != 0)
+ ofs = 90;
+ else
+ ofs = -90;
+
+ if (M.M_walkmove(self, self.ideal_yaw + ofs, distance))
+ return;
+
+ self.monsterinfo.lefty = 1 - self.monsterinfo.lefty;
+ M.M_walkmove(self, self.ideal_yaw - ofs, distance);
+ }
+
+ /*
+ =============
+ ai_checkattack
+
+ Decides if we're going to attack or do something else
+ used by ai_run and ai_stand
+ =============
+ */
+ public static boolean ai_checkattack(edict_t self, float dist) {
+ float temp[] = { 0, 0, 0 };
+
+ boolean hesDeadJim;
+
+ // this causes monsters to run blindly to the combat point w/o firing
+ if (self.goalentity != null) {
+ if ((self.monsterinfo.aiflags & AI_COMBAT_POINT) != 0)
+ return false;
+
+ if ((self.monsterinfo.aiflags & AI_SOUND_TARGET) != 0) {
+ if ((level.time - self.enemy.teleport_time) > 5.0) {
+ if (self.goalentity == self.enemy)
+ if (self.movetarget != null)
+ self.goalentity = self.movetarget;
+ else
+ self.goalentity = null;
+ self.monsterinfo.aiflags &= ~AI_SOUND_TARGET;
+ if ((self.monsterinfo.aiflags & AI_TEMP_STAND_GROUND) != 0)
+ self.monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+ }
+ else {
+ self.show_hostile = (int) level.time + 1;
+ return false;
+ }
+ }
+ }
+
+ enemy_vis = false;
+
+ // see if the enemy is dead
+ hesDeadJim = false;
+ if ((null == self.enemy) || (self.enemy.inuse)) {
+ hesDeadJim = true;
+ }
+ else if ((self.monsterinfo.aiflags & AI_MEDIC) != 0) {
+ if (self.enemy.health > 0) {
+ hesDeadJim = true;
+ self.monsterinfo.aiflags &= ~AI_MEDIC;
+ }
+ }
+ else {
+ if ((self.monsterinfo.aiflags & AI_BRUTAL) != 0) {
+ if (self.enemy.health <= -80)
+ hesDeadJim = true;
+ }
+ else {
+ if (self.enemy.health <= 0)
+ hesDeadJim = true;
+ }
+ }
+
+ if (hesDeadJim) {
+ self.enemy = null;
+ // FIXME: look all around for other targets
+ if (self.oldenemy != null && self.oldenemy.health > 0) {
+ self.enemy = self.oldenemy;
+ self.oldenemy = null;
+ HuntTarget(self);
+ }
+ else {
+ if (self.movetarget != null) {
+ self.goalentity = self.movetarget;
+ self.monsterinfo.walk.think(self);
+ }
+ else {
+ // we need the pausetime otherwise the stand code
+ // will just revert to walking with no target and
+ // the monsters will wonder around aimlessly trying
+ // to hunt the world entity
+ self.monsterinfo.pausetime = level.time + 100000000;
+ self.monsterinfo.stand.think(self);
+ }
+ return true;
+ }
+ }
+
+ self.show_hostile = (int) level.time + 1; // wake up other monsters
+
+ // check knowledge of enemy
+ enemy_vis = visible(self, self.enemy);
+ if (enemy_vis) {
+ self.monsterinfo.search_time = level.time + 5;
+ Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting);
+ }
+
+ // look for other coop players here
+ // if (coop && self.monsterinfo.search_time < level.time)
+ // {
+ // if (FindTarget (self))
+ // return true;
+ // }
+
+ enemy_infront = infront(self, self.enemy);
+ enemy_range = range(self, self.enemy);
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp);
+ enemy_yaw = Math3D.vectoyaw(temp);
+
+ // JDC self.ideal_yaw = enemy_yaw;
+
+ if (self.monsterinfo.attack_state == AS_MISSILE) {
+ ai_run_missile(self);
+ return true;
+ }
+ if (self.monsterinfo.attack_state == AS_MELEE) {
+ ai_run_melee(self);
+ return true;
+ }
+
+ // if enemy is not currently visible, we will never attack
+ if (!enemy_vis)
+ return false;
+
+ return self.monsterinfo.checkattack.think(self);
+ }
+
+ /*
+ =============
+ ai_run
+
+ The monster has an enemy it is trying to kill
+ =============
+ */
+ public static AIAdapter ai_run = new AIAdapter() {
+ public void ai_run(edict_t self, float dist) {
+ float[] v = { 0, 0, 0 };
+
+ edict_t tempgoal;
+ edict_t save;
+ boolean new1;
+ edict_t marker;
+ float d1, d2;
+ trace_t tr;
+ float[] v_forward = { 0, 0, 0 }, v_right = { 0, 0, 0 };
+ float left, center, right;
+ float[] left_target = { 0, 0, 0 }, right_target = { 0, 0, 0 };
+
+ // if we're going to a combat point, just proceed
+ if ((self.monsterinfo.aiflags & AI_COMBAT_POINT) != 0) {
+ M.M_MoveToGoal(self, dist);
+ return;
+ }
+
+ if ((self.monsterinfo.aiflags & AI_SOUND_TARGET) != 0) {
+ Math3D.VectorSubtract(self.s.origin, self.enemy.s.origin, v);
+ if (Math3D.VectorLength(v) < 64) {
+ self.monsterinfo.aiflags |= (AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
+ self.monsterinfo.stand.think(self);
+ return;
+ }
+
+ M.M_MoveToGoal(self, dist);
+
+ if (!FindTarget(self))
+ return;
+ }
+
+ if (ai_checkattack(self, dist))
+ return;
+
+ if (self.monsterinfo.attack_state == AS_SLIDING) {
+ ai_run_slide(self, dist);
+ return;
+ }
+
+ if (enemy_vis) {
+ // if (self.aiflags & AI_LOST_SIGHT)
+ // dprint("regained sight\n");
+ M.M_MoveToGoal(self, dist);
+ self.monsterinfo.aiflags &= ~AI_LOST_SIGHT;
+ Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting);
+ self.monsterinfo.trail_time = level.time;
+ return;
+ }
+
+ // coop will change to another enemy if visible
+ if (coop.value != 0) {
+ // FIXME: insane guys get mad with this, which causes crashes!
+ if (FindTarget(self))
+ return;
+ }
+
+ if ((self.monsterinfo.search_time != 0) && (level.time > (self.monsterinfo.search_time + 20))) {
+ M.M_MoveToGoal(self, dist);
+ self.monsterinfo.search_time = 0;
+ // dprint("search timeout\n");
+ return;
+ }
+
+ save = self.goalentity;
+ tempgoal = G_Spawn();
+ self.goalentity = tempgoal;
+
+ new1 = false;
+
+ if (0 == (self.monsterinfo.aiflags & AI_LOST_SIGHT)) {
+ // just lost sight of the player, decide where to go first
+ // dprint("lost sight of player, last seen at "); dprint(vtos(self.last_sighting)); dprint("\n");
+ self.monsterinfo.aiflags |= (AI_LOST_SIGHT | AI_PURSUIT_LAST_SEEN);
+ self.monsterinfo.aiflags &= ~(AI_PURSUE_NEXT | AI_PURSUE_TEMP);
+ new1 = true;
+ }
+
+ if ((self.monsterinfo.aiflags & AI_PURSUE_NEXT) != 0) {
+ self.monsterinfo.aiflags &= ~AI_PURSUE_NEXT;
+ // dprint("reached current goal: "); dprint(vtos(self.origin)); dprint(" "); dprint(vtos(self.last_sighting)); dprint(" "); dprint(ftos(vlen(self.origin - self.last_sighting))); dprint("\n");
+
+ // give ourself more time since we got this far
+ self.monsterinfo.search_time = level.time + 5;
+
+ if ((self.monsterinfo.aiflags & AI_PURSUE_TEMP) != 0) {
+ // dprint("was temp goal; retrying original\n");
+ self.monsterinfo.aiflags &= ~AI_PURSUE_TEMP;
+ marker = null;
+ Math3D.VectorCopy(self.monsterinfo.saved_goal, self.monsterinfo.last_sighting);
+ new1 = true;
+ }
+ else if ((self.monsterinfo.aiflags & AI_PURSUIT_LAST_SEEN) != 0) {
+ self.monsterinfo.aiflags &= ~AI_PURSUIT_LAST_SEEN;
+ marker = PlayerTrail.PickFirst(self);
+ }
+ else {
+ marker = PlayerTrail.PickNext(self);
+ }
+
+ if (marker != null) {
+ Math3D.VectorCopy(marker.s.origin, self.monsterinfo.last_sighting);
+ self.monsterinfo.trail_time = marker.timestamp;
+ self.s.angles[YAW] = self.ideal_yaw = marker.s.angles[YAW];
+ // dprint("heading is "); dprint(ftos(self.ideal_yaw)); dprint("\n");
+
+ // debug_drawline(self.origin, self.last_sighting, 52);
+ new1 = true;
+ }
+ }
+
+ Math3D.VectorSubtract(self.s.origin, self.monsterinfo.last_sighting, v);
+ d1 = Math3D.VectorLength(v);
+ if (d1 <= dist) {
+ self.monsterinfo.aiflags |= AI_PURSUE_NEXT;
+ dist = d1;
+ }
+
+ Math3D.VectorCopy(self.monsterinfo.last_sighting, self.goalentity.s.origin);
+
+ if (new1) {
+ // gi.dprintf("checking for course correction\n");
+
+ tr = gi.trace(self.s.origin, self.mins, self.maxs, self.monsterinfo.last_sighting, self, MASK_PLAYERSOLID);
+ if (tr.fraction < 1) {
+ Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
+ d1 = Math3D.VectorLength(v);
+ center = tr.fraction;
+ d2 = d1 * ((center + 1) / 2);
+ self.s.angles[YAW] = self.ideal_yaw = Math3D.vectoyaw(v);
+ Math3D.AngleVectors(self.s.angles, v_forward, v_right, null);
+
+ Math3D.VectorSet(v, d2, -16, 0);
+ Math3D.G_ProjectSource(self.s.origin, v, v_forward, v_right, left_target);
+ tr = gi.trace(self.s.origin, self.mins, self.maxs, left_target, self, MASK_PLAYERSOLID);
+ left = tr.fraction;
+
+ Math3D.VectorSet(v, d2, 16, 0);
+ Math3D.G_ProjectSource(self.s.origin, v, v_forward, v_right, right_target);
+ tr = gi.trace(self.s.origin, self.mins, self.maxs, right_target, self, MASK_PLAYERSOLID);
+ right = tr.fraction;
+
+ center = (d1 * center) / d2;
+ if (left >= center && left > right) {
+ if (left < 1) {
+ Math3D.VectorSet(v, d2 * left * 0.5f, -16f, 0f);
+ Math3D.G_ProjectSource(self.s.origin, v, v_forward, v_right, left_target);
+ // gi.dprintf("incomplete path, go part way and adjust again\n");
+ }
+ Math3D.VectorCopy(self.monsterinfo.last_sighting, self.monsterinfo.saved_goal);
+ self.monsterinfo.aiflags |= AI_PURSUE_TEMP;
+ Math3D.VectorCopy(left_target, self.goalentity.s.origin);
+ Math3D.VectorCopy(left_target, self.monsterinfo.last_sighting);
+ Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
+ self.s.angles[YAW] = self.ideal_yaw = Math3D.vectoyaw(v);
+ // gi.dprintf("adjusted left\n");
+ // debug_drawline(self.origin, self.last_sighting, 152);
+ }
+ else if (right >= center && right > left) {
+ if (right < 1) {
+ Math3D.VectorSet(v, d2 * right * 0.5f, 16f, 0f);
+ Math3D.G_ProjectSource(self.s.origin, v, v_forward, v_right, right_target);
+ // gi.dprintf("incomplete path, go part way and adjust again\n");
+ }
+ Math3D.VectorCopy(self.monsterinfo.last_sighting, self.monsterinfo.saved_goal);
+ self.monsterinfo.aiflags |= AI_PURSUE_TEMP;
+ Math3D.VectorCopy(right_target, self.goalentity.s.origin);
+ Math3D.VectorCopy(right_target, self.monsterinfo.last_sighting);
+ Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
+ self.s.angles[YAW] = self.ideal_yaw = Math3D.vectoyaw(v);
+ // gi.dprintf("adjusted right\n");
+ // debug_drawline(self.origin, self.last_sighting, 152);
+ }
+ }
+ // else gi.dprintf("course was fine\n");
+ }
+
+ M.M_MoveToGoal(self, dist);
+
+ G_FreeEdict(tempgoal);
+
+ if (self != null)
+ self.goalentity = save;
+ }
+ };
+
+ public static void UpdateChaseCam(edict_t ent) {
+ float[] o = { 0, 0, 0 }, ownerv = { 0, 0, 0 }, goal = { 0, 0, 0 };
+ edict_t targ;
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 };
+ trace_t trace;
+ int i;
+ float[] oldgoal = { 0, 0, 0 };
+ float[] angles = { 0, 0, 0 };
+
+ // is our chase target gone?
+ if (!ent.client.chase_target.inuse || ent.client.chase_target.client.resp.spectator) {
+ edict_t old = ent.client.chase_target;
+ ChaseNext(ent);
+ if (ent.client.chase_target == old) {
+ ent.client.chase_target = null;
+ ent.client.ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
+ return;
+ }
+ }
+
+ targ = ent.client.chase_target;
+
+ Math3D.VectorCopy(targ.s.origin, ownerv);
+ Math3D.VectorCopy(ent.s.origin, oldgoal);
+
+ ownerv[2] += targ.viewheight;
+
+ Math3D.VectorCopy(targ.client.v_angle, angles);
+ if (angles[PITCH] > 56)
+ angles[PITCH] = 56;
+ Math3D.AngleVectors(angles, forward, right, null);
+ Math3D.VectorNormalize(forward);
+ Math3D.VectorMA(ownerv, -30, forward, o);
+
+ if (o[2] < targ.s.origin[2] + 20)
+ o[2] = targ.s.origin[2] + 20;
+
+ // jump animation lifts
+ if (targ.groundentity == null)
+ o[2] += 16;
+
+ trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+
+ Math3D.VectorCopy(trace.endpos, goal);
+
+ Math3D.VectorMA(goal, 2, forward, goal);
+
+ // pad for floors and ceilings
+ Math3D.VectorCopy(goal, o);
+ o[2] += 6;
+ trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+ if (trace.fraction < 1) {
+ Math3D.VectorCopy(trace.endpos, goal);
+ goal[2] -= 6;
+ }
+
+ Math3D.VectorCopy(goal, o);
+ o[2] -= 6;
+ trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
+ if (trace.fraction < 1) {
+ Math3D.VectorCopy(trace.endpos, goal);
+ goal[2] += 6;
+ }
+
+ if (targ.deadflag != 0)
+ ent.client.ps.pmove.pm_type = PM_DEAD;
+ else
+ ent.client.ps.pmove.pm_type = PM_FREEZE;
+
+ Math3D.VectorCopy(goal, ent.s.origin);
+ for (i = 0; i < 3; i++)
+ ent.client.ps.pmove.delta_angles[i] = (short) Math3D.ANGLE2SHORT(targ.client.v_angle[i] - ent.client.resp.cmd_angles[i]);
+
+ if (targ.deadflag != 0) {
+ ent.client.ps.viewangles[ROLL] = 40;
+ ent.client.ps.viewangles[PITCH] = -15;
+ ent.client.ps.viewangles[YAW] = targ.client.killer_yaw;
+ }
+ else {
+ Math3D.VectorCopy(targ.client.v_angle, ent.client.ps.viewangles);
+ Math3D.VectorCopy(targ.client.v_angle, ent.client.v_angle);
+ }
+
+ ent.viewheight = 0;
+ ent.client.ps.pmove.pm_flags |= PMF_NO_PREDICTION;
+ gi.linkentity(ent);
+ }
+
+ public static void ChaseNext(edict_t ent) {
+ int i;
+ edict_t e;
+
+ if (null == ent.client.chase_target)
+ return;
+
+ i = ent.client.chase_target.index;
+ do {
+ i++;
+ if (i > maxclients.value)
+ i = 1;
+ e = g_edicts[i];
+
+ if (!e.inuse)
+ continue;
+ if (!e.client.resp.spectator)
+ break;
+ }
+ while (e != ent.client.chase_target);
+
+ ent.client.chase_target = e;
+ ent.client.update_chase = true;
+ }
+
+ public static void ChasePrev(edict_t ent) {
+ int i;
+ edict_t e;
+
+ if (ent.client.chase_target == null)
+ return;
+
+ i = ent.client.chase_target.index;
+ do {
+ i--;
+ if (i < 1)
+ i = (int) maxclients.value;
+ e = g_edicts[i];
+ if (!e.inuse)
+ continue;
+ if (!e.client.resp.spectator)
+ break;
+ }
+ while (e != ent.client.chase_target);
+
+ ent.client.chase_target = e;
+ ent.client.update_chase = true;
+ }
+
+ public static void GetChaseTarget(edict_t ent) {
+ int i;
+ edict_t other;
+
+ for (i = 1; i <= maxclients.value; i++) {
+ other = g_edicts[i];
+ if (other.inuse && !other.client.resp.spectator) {
+ ent.client.chase_target = other;
+ ent.client.update_chase = true;
+ UpdateChaseCam(ent);
+ return;
+ }
+ }
+ gi.centerprintf(ent, "No other players to chase.");
+ }
+
+ /*
+ ===============
+ SetItemNames
+
+ Called by worldspawn
+ ===============
+ */
+ public static void SetItemNames() {
+ int i;
+ gitem_t it;
+
+ for (i = 1; i < game.num_items; i++) {
+ it = itemlist[i];
+ gi.configstring(CS_ITEMS + i, it.pickup_name);
+ }
+
+ jacket_armor_index = ITEM_INDEX(FindItem("Jacket Armor"));
+ combat_armor_index = ITEM_INDEX(FindItem("Combat Armor"));
+ body_armor_index = ITEM_INDEX(FindItem("Body Armor"));
+ power_screen_index = ITEM_INDEX(FindItem("Power Screen"));
+ power_shield_index = ITEM_INDEX(FindItem("Power Shield"));
+ }
+
+ public static void SelectNextItem(edict_t ent, int itflags) {
+ gclient_t cl;
+ int i, index;
+ gitem_t it;
+
+ cl = ent.client;
+
+ if (cl.chase_target != null) {
+ ChaseNext(ent);
+ return;
+ }
+
+ // scan for the next valid one
+ for (i = 1; i <= MAX_ITEMS; i++) {
+ index = (cl.pers.selected_item + i) % MAX_ITEMS;
+ if (0 == cl.pers.inventory[index])
+ continue;
+ it = itemlist[index];
+ if (it.use == null)
+ continue;
+ if (0 == (it.flags & itflags))
+ continue;
+
+ cl.pers.selected_item = index;
+ return;
+ }
+
+ cl.pers.selected_item = -1;
+ }
+
+ public static void SelectPrevItem(edict_t ent, int itflags) {
+ gclient_t cl;
+ int i, index;
+ gitem_t it;
+
+ cl = ent.client;
+
+ if (cl.chase_target != null) {
+ ChasePrev(ent);
+ return;
+ }
+
+ // scan for the next valid one
+ for (i = 1; i <= MAX_ITEMS; i++) {
+ index = (cl.pers.selected_item + MAX_ITEMS - i) % MAX_ITEMS;
+ if (0 == cl.pers.inventory[index])
+ continue;
+ it = itemlist[index];
+ if (null == it.use)
+ continue;
+ if (0 == (it.flags & itflags))
+ continue;
+
+ cl.pers.selected_item = index;
+ return;
+ }
+
+ cl.pers.selected_item = -1;
+ }
+
+ public static void ValidateSelectedItem(edict_t ent) {
+ gclient_t cl;
+
+ cl = ent.client;
+
+ if (cl.pers.inventory[cl.pers.selected_item] != 0)
+ return; // valid
+
+ SelectNextItem(ent, -1);
+ }
+
+ //======================================================================
+
+ public static boolean Add_Ammo(edict_t ent, gitem_t item, int count) {
+ int index;
+ int max;
+
+ if (null == ent.client)
+ return false;
+
+ if (item.tag == AMMO_BULLETS)
+ max = ent.client.pers.max_bullets;
+ else if (item.tag == AMMO_SHELLS)
+ max = ent.client.pers.max_shells;
+ else if (item.tag == AMMO_ROCKETS)
+ max = ent.client.pers.max_rockets;
+ else if (item.tag == AMMO_GRENADES)
+ max = ent.client.pers.max_grenades;
+ else if (item.tag == AMMO_CELLS)
+ max = ent.client.pers.max_cells;
+ else if (item.tag == AMMO_SLUGS)
+ max = ent.client.pers.max_slugs;
+ else
+ return false;
+
+ index = ITEM_INDEX(item);
+
+ if (ent.client.pers.inventory[index] == max)
+ return false;
+
+ ent.client.pers.inventory[index] += count;
+
+ if (ent.client.pers.inventory[index] > max)
+ ent.client.pers.inventory[index] = max;
+
+ return true;
+ }
+
+ /*
+ ===============
+ PrecacheItem
+
+ Precaches all data needed for a given item.
+ This will be called for each item spawned in a level,
+ and for each item in each client's inventory.
+ ===============
+ */
+ public static void PrecacheItem(gitem_t it) {
+ String s;
+ String data;
+ int len;
+ gitem_t ammo;
+
+ if (it == null)
+ return;
+
+ if (it.pickup_sound != null)
+ gi.soundindex(it.pickup_sound);
+
+ if (it.world_model != null)
+ gi.modelindex(it.world_model);
+
+ if (it.view_model != null)
+ gi.modelindex(it.view_model);
+
+ if (it.icon != null)
+ gi.imageindex(it.icon);
+
+ // parse everything for its ammo
+ if (it.ammo != null && it.ammo.length() != 0) {
+ ammo = FindItem(it.ammo);
+ if (ammo != it)
+ PrecacheItem(ammo);
+ }
+
+ // parse the space seperated precache string for other items
+ s = it.precaches;
+ if (s == null || s.length() != 0)
+ return;
+
+ StringTokenizer tk = new StringTokenizer(s);
+
+
+ while (tk.hasMoreTokens()) {
+ data = tk.nextToken();
+
+ len = data.length();
+
+ if (len >= MAX_QPATH || len < 5)
+ gi.error("PrecacheItem: it.classname has bad precache string: " + s);
+
+ // determine type based on extension
+ if (data.endsWith("md2"))
+ gi.modelindex(data);
+ else if (data.endsWith("sp2"))
+ gi.modelindex(data);
+ else if (data.endsWith("wav"))
+ gi.soundindex(data);
+ else if (data.endsWith("pcx"))
+ gi.imageindex(data);
+ else
+ gi.error("PrecacheItem: bad precache string: " + data);
+ }
+ }
+
+ public static EntInteractAdapter Pickup_Ammo = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+ int oldcount;
+ int count;
+ boolean weapon;
+
+ weapon = (ent.item.flags & IT_WEAPON) != 0;
+ if ((weapon) && ((int) dmflags.value & DF_INFINITE_AMMO) != 0)
+ count = 1000;
+ else if (ent.count != 0)
+ count = ent.count;
+ else
+ count = ent.item.quantity;
+
+ oldcount = other.client.pers.inventory[ITEM_INDEX(ent.item)];
+
+ if (!Add_Ammo(other, ent.item, count))
+ return false;
+
+ if (weapon && 0 == oldcount) {
+ if (other.client.pers.weapon != ent.item
+ && (0 == deathmatch.value || other.client.pers.weapon == FindItem("blaster")))
+ other.client.newweapon = ent.item;
+ }
+
+ if (0 == (ent.spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) && (deathmatch.value != 0))
+ SetRespawn(ent, 30);
+ return true;
+ }
+ };
+
+ public static EntInteractAdapter Pickup_Armor = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+ int old_armor_index;
+ gitem_armor_t oldinfo;
+ gitem_armor_t newinfo;
+ int newcount;
+ float salvage;
+ int salvagecount;
+
+ // get info on new armor
+ newinfo = (gitem_armor_t) ent.item.info;
+
+ old_armor_index = ArmorIndex(other);
+
+ // handle armor shards specially
+ if (ent.item.tag == ARMOR_SHARD) {
+ if (0 == old_armor_index)
+ other.client.pers.inventory[jacket_armor_index] = 2;
+ else
+ other.client.pers.inventory[old_armor_index] += 2;
+ }
+
+ // if player has no armor, just use it
+ else if (0 == old_armor_index) {
+ other.client.pers.inventory[ITEM_INDEX(ent.item)] = newinfo.base_count;
+ }
+
+ // use the better armor
+ else {
+ // get info on old armor
+ if (old_armor_index == jacket_armor_index)
+ oldinfo = jacketarmor_info;
+
+ else if (old_armor_index == combat_armor_index)
+ oldinfo = combatarmor_info;
+
+ else // (old_armor_index == body_armor_index)
+ oldinfo = bodyarmor_info;
+
+ if (newinfo.normal_protection > oldinfo.normal_protection) {
+ // calc new armor values
+ salvage = oldinfo.normal_protection / newinfo.normal_protection;
+ salvagecount = (int) salvage * other.client.pers.inventory[old_armor_index];
+ newcount = newinfo.base_count + salvagecount;
+ if (newcount > newinfo.max_count)
+ newcount = newinfo.max_count;
+
+ // zero count of old armor so it goes away
+ other.client.pers.inventory[old_armor_index] = 0;
+
+ // change armor to new item with computed value
+ other.client.pers.inventory[ITEM_INDEX(ent.item)] = newcount;
+ }
+ else {
+ // calc new armor values
+ salvage = newinfo.normal_protection / oldinfo.normal_protection;
+ salvagecount = (int) salvage * newinfo.base_count;
+ newcount = other.client.pers.inventory[old_armor_index] + salvagecount;
+ if (newcount > oldinfo.max_count)
+ newcount = oldinfo.max_count;
+
+ // if we're already maxed out then we don't need the new armor
+ if (other.client.pers.inventory[old_armor_index] >= newcount)
+ return false;
+
+ // update current armor value
+ other.client.pers.inventory[old_armor_index] = newcount;
+ }
+ }
+
+ if (0 == (ent.spawnflags & DROPPED_ITEM) && (deathmatch.value == 0))
+ SetRespawn(ent, 20);
+
+ return true;
+ }
+ };
+
+ public static EntInteractAdapter Pickup_PowerArmor = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+
+ int quantity;
+
+ quantity = other.client.pers.inventory[ITEM_INDEX(ent.item)];
+
+ other.client.pers.inventory[ITEM_INDEX(ent.item)]++;
+
+ if (deathmatch.value != 0) {
+ if (0 == (ent.spawnflags & DROPPED_ITEM))
+ SetRespawn(ent, ent.item.quantity);
+ // auto-use for DM only if we didn't already have one
+ if (0 == quantity)
+ ent.item.use.use(other, ent.item);
+ }
+ return true;
+ }
+ };
+
+ // ======================================================================
+
+ public static EntInteractAdapter Pickup_Powerup = new EntInteractAdapter() {
+
+ public boolean interact(edict_t ent, edict_t other) {
+ int quantity;
+
+ quantity = other.client.pers.inventory[ITEM_INDEX(ent.item)];
+ if ((skill.value == 1 && quantity >= 2) || (skill.value >= 2 && quantity >= 1))
+ return false;
+
+ if ((coop.value != 0) && (ent.item.flags & IT_STAY_COOP) != 0 && (quantity > 0))
+ return false;
+
+ other.client.pers.inventory[ITEM_INDEX(ent.item)]++;
+
+ if (deathmatch.value != 0) {
+ if (0 == (ent.spawnflags & DROPPED_ITEM))
+ SetRespawn(ent, ent.item.quantity);
+ if (((int) dmflags.value & DF_INSTANT_ITEMS) != 0
+ || ((ent.item.use == Use_Quad) && 0 != (ent.spawnflags & DROPPED_PLAYER_ITEM))) {
+ if ((ent.item.use == Use_Quad) && 0 != (ent.spawnflags & DROPPED_PLAYER_ITEM))
+ quad_drop_timeout_hack = (int) ((ent.nextthink - level.time) / FRAMETIME);
+
+ ent.item.use.use(other, ent.item);
+ }
+ }
+
+ return true;
+ }
+ };
+
+ public static EntInteractAdapter Pickup_Adrenaline = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+ if (deathmatch.value == 0)
+ other.max_health += 1;
+
+ if (other.health < other.max_health)
+ other.health = other.max_health;
+
+ if (0 == (ent.spawnflags & DROPPED_ITEM) && (deathmatch.value != 0))
+ SetRespawn(ent, ent.item.quantity);
+
+ return true;
+
+ }
+ };
+
+ public static EntInteractAdapter Pickup_AncientHead = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+ other.max_health += 2;
+
+ if (0 == (ent.spawnflags & DROPPED_ITEM) && (deathmatch.value != 0))
+ SetRespawn(ent, ent.item.quantity);
+
+ return true;
+ }
+ };
+
+ public static EntInteractAdapter Pickup_Bandolier = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+ gitem_t item;
+ int index;
+
+ if (other.client.pers.max_bullets < 250)
+ other.client.pers.max_bullets = 250;
+ if (other.client.pers.max_shells < 150)
+ other.client.pers.max_shells = 150;
+ if (other.client.pers.max_cells < 250)
+ other.client.pers.max_cells = 250;
+ if (other.client.pers.max_slugs < 75)
+ other.client.pers.max_slugs = 75;
+
+ item = FindItem("Bullets");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_bullets)
+ other.client.pers.inventory[index] = other.client.pers.max_bullets;
+ }
+
+ item = FindItem("Shells");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_shells)
+ other.client.pers.inventory[index] = other.client.pers.max_shells;
+ }
+
+ if (0 == (ent.spawnflags & DROPPED_ITEM) && (deathmatch.value != 0))
+ SetRespawn(ent, ent.item.quantity);
+
+ return true;
+
+ }
+ };
+
+ public static EntUseAdapter Use_Item = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ ent.svflags &= ~SVF_NOCLIENT;
+ ent.use = null;
+
+ if ((ent.spawnflags & ITEM_NO_TOUCH) != 0) {
+ ent.solid = SOLID_BBOX;
+ ent.touch = null;
+ }
+ else {
+ ent.solid = SOLID_TRIGGER;
+ ent.touch = Touch_Item;
+ }
+
+ gi.linkentity(ent);
+ }
+ };
+
+ /*
+ ================
+ droptofloor
+ ================
+ */
+
+ public static EntThinkAdapter droptofloor = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ trace_t tr;
+ float[] dest = { 0, 0, 0 };
+
+ float v[];
+
+ v = Lib.tv(-15, -15, -15);
+ Math3D.VectorCopy(v, ent.mins);
+ v = Lib.tv(15, 15, 15);
+ Math3D.VectorCopy(v, ent.maxs);
+
+ if (ent.model != null)
+ gi.setmodel(ent, ent.model);
+ else
+ gi.setmodel(ent, ent.item.world_model);
+ ent.solid = SOLID_TRIGGER;
+ ent.movetype = MOVETYPE_TOSS;
+ ent.touch = Touch_Item;
+
+ v = Lib.tv(0, 0, -128);
+ Math3D.VectorAdd(ent.s.origin, v, dest);
+
+ tr = gi.trace(ent.s.origin, ent.mins, ent.maxs, dest, ent, MASK_SOLID);
+ if (tr.startsolid) {
+ gi.dprintf("droptofloor: " + ent.classname + " startsolid at " + Lib.vtos(ent.s.origin) + "\n");
+ G_FreeEdict(ent);
+ return true;
+ }
+
+ Math3D.VectorCopy(tr.endpos, ent.s.origin);
+
+ if (ent.team != null) {
+ ent.flags &= ~FL_TEAMSLAVE;
+ ent.chain = ent.teamchain;
+ ent.teamchain = null;
+
+ ent.svflags |= SVF_NOCLIENT;
+ ent.solid = SOLID_NOT;
+ if (ent == ent.teammaster) {
+ ent.nextthink = level.time + FRAMETIME;
+ ent.think = DoRespawn;
+ }
+ }
+
+ if ((ent.spawnflags & ITEM_NO_TOUCH) != 0) {
+ ent.solid = SOLID_BBOX;
+ ent.touch = null;
+ ent.s.effects &= ~EF_ROTATE;
+ ent.s.renderfx &= ~RF_GLOW;
+ }
+
+ if ((ent.spawnflags & ITEM_TRIGGER_SPAWN) != 0) {
+ ent.svflags |= SVF_NOCLIENT;
+ ent.solid = SOLID_NOT;
+ ent.use = Use_Item;
+ }
+
+ gi.linkentity(ent);
+ return true;
+ }
+ };
+
+ /*
+ ============
+ SpawnItem
+
+ Sets the clipping size and plants the object on the floor.
+
+ Items can't be immediately dropped to floor, because they might
+ be on an entity that hasn't spawned yet.
+ ============
+ */
+ public static void SpawnItem(edict_t ent, gitem_t item) {
+ PrecacheItem(item);
+
+ if (ent.spawnflags != 0) {
+ if (Lib.strcmp(ent.classname, "key_power_cube") != 0) {
+ ent.spawnflags = 0;
+ gi.dprintf("" + ent.classname + " at " + Lib.vtos(ent.s.origin) + " has invalid spawnflags set\n");
+ }
+ }
+
+ // some items will be prevented in deathmatch
+ if (deathmatch.value != 0) {
+ if (((int) dmflags.value & DF_NO_ARMOR) != 0) {
+ if (item.pickup == Pickup_Armor || item.pickup == Pickup_PowerArmor) {
+ G_FreeEdict(ent);
+ return;
+ }
+ }
+ if (((int) dmflags.value & DF_NO_ITEMS) != 0) {
+ if (item.pickup == Pickup_Powerup) {
+ G_FreeEdict(ent);
+ return;
+ }
+ }
+ if (((int) dmflags.value & DF_NO_HEALTH) != 0) {
+ if (item.pickup == Pickup_Health || item.pickup == Pickup_Adrenaline || item.pickup == Pickup_AncientHead) {
+ G_FreeEdict(ent);
+ return;
+ }
+ }
+ if (((int) dmflags.value & DF_INFINITE_AMMO) != 0) {
+ if ((item.flags == IT_AMMO) || (Lib.strcmp(ent.classname, "weapon_bfg") == 0)) {
+ G_FreeEdict(ent);
+ return;
+ }
+ }
+ }
+
+ if (coop.value != 0 && (Lib.strcmp(ent.classname, "key_power_cube") == 0)) {
+ ent.spawnflags |= (1 << (8 + level.power_cubes));
+ level.power_cubes++;
+ }
+
+ // don't let them drop items that stay in a coop game
+ if ((coop.value != 0) && (item.flags & IT_STAY_COOP) != 0) {
+ item.drop = null;
+ }
+
+ ent.item = item;
+ ent.nextthink = level.time + 2 * FRAMETIME;
+ // items start after other solids
+ ent.think = droptofloor;
+ ent.s.effects = item.world_model_flags;
+ ent.s.renderfx = RF_GLOW;
+
+ if (ent.model != null)
+ gi.modelindex(ent.model);
+ }
+
+ /*
+ ===============
+ Touch_Item
+ ===============
+ */
+ public static void Touch_Item(edict_t ent, edict_t other, cplane_t plane, csurface_t surf) {
+ boolean taken;
+
+ if (other.client == null)
+ return;
+ if (other.health < 1)
+ return; // dead people can't pickup
+ if (ent.item.pickup == null)
+ return; // not a grabbable item?
+
+ taken = ent.item.pickup.interact(ent, other);
+
+ if (taken) {
+ // flash the screen
+ other.client.bonus_alpha = 0.25f;
+
+ // show icon and name on status bar
+ other.client.ps.stats[STAT_PICKUP_ICON] = (short) gi.imageindex(ent.item.icon);
+ other.client.ps.stats[STAT_PICKUP_STRING] = (short) (CS_ITEMS + ITEM_INDEX(ent.item));
+ other.client.pickup_msg_time = level.time + 3.0f;
+
+ // change selected item
+ if (ent.item.use != null)
+ other.client.pers.selected_item = other.client.ps.stats[STAT_SELECTED_ITEM] = (short) ITEM_INDEX(ent.item);
+
+ if (ent.item.pickup == Pickup_Health) {
+ if (ent.count == 2)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/s_health.wav"), 1, ATTN_NORM, 0);
+ else if (ent.count == 10)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/n_health.wav"), 1, ATTN_NORM, 0);
+ else if (ent.count == 25)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/l_health.wav"), 1, ATTN_NORM, 0);
+ else // (ent.count == 100)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/m_health.wav"), 1, ATTN_NORM, 0);
+ }
+ else if (ent.item.pickup_sound != null) {
+ gi.sound(other, CHAN_ITEM, gi.soundindex(ent.item.pickup_sound), 1, ATTN_NORM, 0);
+ }
+ }
+
+ if (0 == (ent.spawnflags & ITEM_TARGETS_USED)) {
+ G_UseTargets(ent, other);
+ ent.spawnflags |= ITEM_TARGETS_USED;
+ }
+
+ if (!taken)
+ return;
+
+ if (!((coop.value != 0) && (ent.item.flags & IT_STAY_COOP) != 0)
+ || 0 != (ent.spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM))) {
+ if ((ent.flags & FL_RESPAWN) != 0)
+ ent.flags &= ~FL_RESPAWN;
+ else
+ G_FreeEdict(ent);
+ }
+ }
+
+ /*
+ ==================
+ LookAtKiller
+ ==================
+ */
+ public static void LookAtKiller(edict_t self, edict_t inflictor, edict_t attacker) {
+ float dir[] = { 0, 0, 0 };
+
+ edict_t world = g_edicts[0];
+
+ if (attacker != null && attacker != world && attacker != self) {
+ Math3D.VectorSubtract(attacker.s.origin, self.s.origin, dir);
+ }
+ else if (inflictor != null && inflictor != world && inflictor != self) {
+ Math3D.VectorSubtract(inflictor.s.origin, self.s.origin, dir);
+ }
+ else {
+ self.client.killer_yaw = self.s.angles[YAW];
+ return;
+ }
+
+ if (dir[0] != 0)
+ self.client.killer_yaw = (float) (180 / Math.PI * Math.atan2(dir[1], dir[0]));
+ else {
+ self.client.killer_yaw = 0;
+ if (dir[1] > 0)
+ self.client.killer_yaw = 90;
+ else if (dir[1] < 0)
+ self.client.killer_yaw = -90;
+ }
+ if (self.client.killer_yaw < 0)
+ self.client.killer_yaw += 360;
+
+ }
+
+ public static void TossClientWeapon(edict_t self) {
+ gitem_t item;
+ edict_t drop;
+ boolean quad;
+ float spread;
+
+ if (deathmatch.value == 0)
+ return;
+
+ item = self.client.pers.weapon;
+ if (0 == self.client.pers.inventory[self.client.ammo_index])
+ item = null;
+ if (item != null && (Lib.strcmp(item.pickup_name, "Blaster") == 0))
+ item = null;
+
+ if (0 == ((int) (dmflags.value) & DF_QUAD_DROP))
+ quad = false;
+ else
+ quad = (self.client.quad_framenum > (level.framenum + 10));
+
+ if (item != null && quad)
+ spread = 22.5f;
+ else
+ spread = 0.0f;
+
+ if (item != null) {
+ self.client.v_angle[YAW] -= spread;
+ drop = Drop_Item(self, item);
+ self.client.v_angle[YAW] += spread;
+ drop.spawnflags = DROPPED_PLAYER_ITEM;
+ }
+
+ if (quad) {
+ self.client.v_angle[YAW] += spread;
+ drop = Drop_Item(self, FindItemByClassname("item_quad"));
+ self.client.v_angle[YAW] -= spread;
+ drop.spawnflags |= DROPPED_PLAYER_ITEM;
+
+ drop.touch = Touch_Item;
+ drop.nextthink = level.time + (self.client.quad_framenum - level.framenum) * FRAMETIME;
+ drop.think = G_FreeEdictA;
+ }
+ }
+
+ public static EntThinkAdapter gib_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.s.frame++;
+ self.nextthink = level.time + FRAMETIME;
+
+ if (self.s.frame == 10) {
+ self.think = G_FreeEdictA;
+ self.nextthink = level.time + 8 + Lib.random() * 10;
+ }
+ return true;
+ }
+ };
+
+ public static EntTouchAdapter gib_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ float[] normal_angles = { 0, 0, 0 }, right = { 0, 0, 0 };
+
+ if (null == self.groundentity)
+ return;
+
+ self.touch = null;
+
+ if (plane != null) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/fhit3.wav"), 1, ATTN_NORM, 0);
+
+ Math3D.vectoangles(plane.normal, normal_angles);
+ Math3D.AngleVectors(normal_angles, null, right, null);
+ Math3D.vectoangles(right, self.s.angles);
+
+ if (self.s.modelindex == sm_meat_index) {
+ self.s.frame++;
+ self.think = gib_think;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ }
+ }
+ };
+
+ public static EntDieAdapter gib_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ G_FreeEdict(self);
+ }
+ };
+
+ public static void ThrowGib(edict_t self, String gibname, int damage, int type) {
+ edict_t gib;
+
+ float[] vd = { 0, 0, 0 };
+ float[] origin = { 0, 0, 0 };
+ float[] size = { 0, 0, 0 };
+ float vscale;
+
+ gib = G_Spawn();
+
+ Math3D.VectorScale(self.size, 0.5f, size);
+ Math3D.VectorAdd(self.absmin, size, origin);
+ gib.s.origin[0] = origin[0] + Lib.crandom() * size[0];
+ gib.s.origin[1] = origin[1] + Lib.crandom() * size[1];
+ gib.s.origin[2] = origin[2] + Lib.crandom() * size[2];
+
+ gi.setmodel(gib, gibname);
+ gib.solid = SOLID_NOT;
+ gib.s.effects |= EF_GIB;
+ gib.flags |= FL_NO_KNOCKBACK;
+ gib.takedamage = DAMAGE_YES;
+ gib.die = gib_die;
+
+ if (type == GIB_ORGANIC) {
+ gib.movetype = MOVETYPE_TOSS;
+ gib.touch = gib_touch;
+ vscale = 0.5f;
+ }
+ else {
+ gib.movetype = MOVETYPE_BOUNCE;
+ vscale = 1.0f;
+ }
+
+ VelocityForDamage(damage, vd);
+ Math3D.VectorMA(self.velocity, vscale, vd, gib.velocity);
+ ClipGibVelocity(gib);
+ gib.avelocity[0] = Lib.random() * 600;
+ gib.avelocity[1] = Lib.random() * 600;
+ gib.avelocity[2] = Lib.random() * 600;
+
+ gib.think = G_FreeEdictA;
+ gib.nextthink = level.time + 10 + Lib.random() * 10;
+
+ gi.linkentity(gib);
+ }
+
+ public static void ThrowHead(edict_t self, String gibname, int damage, int type) {
+ float vd[] = { 0, 0, 0 };
+
+ float vscale;
+
+ self.s.skinnum = 0;
+ self.s.frame = 0;
+ Math3D.VectorClear(self.mins);
+ Math3D.VectorClear(self.maxs);
+
+ self.s.modelindex2 = 0;
+ gi.setmodel(self, gibname);
+ self.solid = SOLID_NOT;
+ self.s.effects |= EF_GIB;
+ self.s.effects &= ~EF_FLIES;
+ self.s.sound = 0;
+ self.flags |= FL_NO_KNOCKBACK;
+ self.svflags &= ~SVF_MONSTER;
+ self.takedamage = DAMAGE_YES;
+ self.die = gib_die;
+
+ if (type == GIB_ORGANIC) {
+ self.movetype = MOVETYPE_TOSS;
+ self.touch = gib_touch;
+ vscale = 0.5f;
+ }
+ else {
+ self.movetype = MOVETYPE_BOUNCE;
+ vscale = 1.0f;
+ }
+
+ VelocityForDamage(damage, vd);
+ Math3D.VectorMA(self.velocity, vscale, vd, self.velocity);
+ ClipGibVelocity(self);
+
+ self.avelocity[YAW] = Lib.crandom() * 600f;
+
+ self.think = G_FreeEdictA;
+ self.nextthink = level.time + 10 + Lib.random() * 10;
+
+ gi.linkentity(self);
+ }
+
+ public static void VelocityForDamage(int damage, float[] v) {
+ v[0] = 100.0f * Lib.crandom();
+ v[1] = 100.0f * Lib.crandom();
+ v[2] = 200.0f + 100.0f * Lib.random();
+
+ if (damage < 50)
+ Math3D.VectorScale(v, 0.7f, v);
+ else
+ Math3D.VectorScale(v, 1.2f, v);
+ }
+
+ public static void ClipGibVelocity(edict_t ent) {
+ if (ent.velocity[0] < -300)
+ ent.velocity[0] = -300;
+ else if (ent.velocity[0] > 300)
+ ent.velocity[0] = 300;
+ if (ent.velocity[1] < -300)
+ ent.velocity[1] = -300;
+ else if (ent.velocity[1] > 300)
+ ent.velocity[1] = 300;
+ if (ent.velocity[2] < 200)
+ ent.velocity[2] = 200; // always some upwards
+ else if (ent.velocity[2] > 500)
+ ent.velocity[2] = 500;
+ }
+
+ public static void ThrowClientHead(edict_t self, int damage) {
+ float vd[] = { 0, 0, 0 };
+ String gibname;
+
+ if ((Lib.rand() & 1) != 0) {
+ gibname = "models/objects/gibs/head2/tris.md2";
+ self.s.skinnum = 1; // second skin is player
+ }
+ else {
+ gibname = "models/objects/gibs/skull/tris.md2";
+ self.s.skinnum = 0;
+ }
+
+ self.s.origin[2] += 32;
+ self.s.frame = 0;
+ gi.setmodel(self, gibname);
+ Math3D.VectorSet(self.mins, -16, -16, 0);
+ Math3D.VectorSet(self.maxs, 16, 16, 16);
+
+ self.takedamage = DAMAGE_NO;
+ self.solid = SOLID_NOT;
+ self.s.effects = EF_GIB;
+ self.s.sound = 0;
+ self.flags |= FL_NO_KNOCKBACK;
+
+ self.movetype = MOVETYPE_BOUNCE;
+ VelocityForDamage(damage, vd);
+ Math3D.VectorAdd(self.velocity, vd, self.velocity);
+
+ if (self.client != null)
+ // bodies in the queue don't have a client anymore
+ {
+ self.client.anim_priority = ANIM_DEATH;
+ self.client.anim_end = self.s.frame;
+ }
+ else {
+ self.think = null;
+ self.nextthink = 0;
+ }
+
+ gi.linkentity(self);
+ }
+
+ /*
+ =================
+ debris
+ =================
+ */
+ public static EntDieAdapter debris_die = new EntDieAdapter() {
+
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ G_FreeEdict(self);
+ }
+ };
+
+ public static void ThrowDebris(edict_t self, String modelname, float speed, float[] origin) {
+ edict_t chunk;
+ float[] v = { 0, 0, 0 };
+
+ chunk = G_Spawn();
+ Math3D.VectorCopy(origin, chunk.s.origin);
+ gi.setmodel(chunk, modelname);
+ v[0] = 100 * Lib.crandom();
+ v[1] = 100 * Lib.crandom();
+ v[2] = 100 + 100 * Lib.crandom();
+ Math3D.VectorMA(self.velocity, speed, v, chunk.velocity);
+ chunk.movetype = MOVETYPE_BOUNCE;
+ chunk.solid = SOLID_NOT;
+ chunk.avelocity[0] = Lib.random() * 600;
+ chunk.avelocity[1] = Lib.random() * 600;
+ chunk.avelocity[2] = Lib.random() * 600;
+ chunk.think = G_FreeEdictA;
+ chunk.nextthink = level.time + 5 + Lib.random() * 5;
+ chunk.s.frame = 0;
+ chunk.flags = 0;
+ chunk.classname = "debris";
+ chunk.takedamage = DAMAGE_YES;
+ chunk.die = debris_die;
+ gi.linkentity(chunk);
+ }
+
+ public static void BecomeExplosion1(edict_t self) {
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_EXPLOSION1);
+ gi.WritePosition(self.s.origin);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+
+ G_FreeEdict(self);
+ }
+
+ public static void BecomeExplosion2(edict_t self) {
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_EXPLOSION2);
+ gi.WritePosition(self.s.origin);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+
+ G_FreeEdict(self);
+ }
+
+ /** Returns true, if the players gender flag was set to female .*/
+ public static boolean IsFemale(edict_t ent) {
+ char info;
+
+ if (null == ent.client)
+ return false;
+
+ info = Info.Info_ValueForKey(ent.client.pers.userinfo, "gender").charAt(0);
+ if (info == 'f' || info == 'F')
+ return true;
+ return false;
+ }
+
+ /** Returns true, if the players gender flag was neither set to female nor to male.*/
+ public static boolean IsNeutral(edict_t ent) {
+ char info;
+
+ if (ent.client == null)
+ return false;
+
+ info = Info.Info_ValueForKey(ent.client.pers.userinfo, "gender").charAt(0);
+
+ if (info != 'f' && info != 'F' && info != 'm' && info != 'M')
+ return true;
+ return false;
+ }
+
+ /** Some reports about the cause of the players death. */
+ public static void ClientObituary(edict_t self, edict_t inflictor, edict_t attacker) {
+ int mod;
+ String message;
+ String message2;
+ boolean ff;
+
+ if (coop.value != 0 && attacker.client != null)
+ meansOfDeath |= MOD_FRIENDLY_FIRE;
+
+ if (deathmatch.value != 0 || coop.value != 0) {
+ ff = (meansOfDeath & MOD_FRIENDLY_FIRE) != 0;
+ mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
+ message = null;
+ message2 = "";
+
+ switch (mod) {
+ case MOD_SUICIDE :
+ message = "suicides";
+ break;
+ case MOD_FALLING :
+ message = "cratered";
+ break;
+ case MOD_CRUSH :
+ message = "was squished";
+ break;
+ case MOD_WATER :
+ message = "sank like a rock";
+ break;
+ case MOD_SLIME :
+ message = "melted";
+ break;
+ case MOD_LAVA :
+ message = "does a back flip into the lava";
+ break;
+ case MOD_EXPLOSIVE :
+ case MOD_BARREL :
+ message = "blew up";
+ break;
+ case MOD_EXIT :
+ message = "found a way out";
+ break;
+ case MOD_TARGET_LASER :
+ message = "saw the light";
+ break;
+ case MOD_TARGET_BLASTER :
+ message = "got blasted";
+ break;
+ case MOD_BOMB :
+ case MOD_SPLASH :
+ case MOD_TRIGGER_HURT :
+ message = "was in the wrong place";
+ break;
+ }
+ if (attacker == self) {
+ switch (mod) {
+ case MOD_HELD_GRENADE :
+ message = "tried to put the pin back in";
+ break;
+ case MOD_HG_SPLASH :
+ case MOD_G_SPLASH :
+ if (IsNeutral(self))
+ message = "tripped on its own grenade";
+ else if (IsFemale(self))
+ message = "tripped on her own grenade";
+ else
+ message = "tripped on his own grenade";
+ break;
+ case MOD_R_SPLASH :
+ if (IsNeutral(self))
+ message = "blew itself up";
+ else if (IsFemale(self))
+ message = "blew herself up";
+ else
+ message = "blew himself up";
+ break;
+ case MOD_BFG_BLAST :
+ message = "should have used a smaller gun";
+ break;
+ default :
+ if (IsNeutral(self))
+ message = "killed itself";
+ else if (IsFemale(self))
+ message = "killed herself";
+ else
+ message = "killed himself";
+ break;
+ }
+ }
+ if (message != null) {
+ gi.bprintf(PRINT_MEDIUM, "" + self.client.pers.netname + " " + message + ".\n");
+ if (deathmatch.value != 0)
+ self.client.resp.score--;
+ self.enemy = null;
+ return;
+ }
+
+ self.enemy = attacker;
+
+ if (attacker != null && attacker.client != null) {
+ switch (mod) {
+ case MOD_BLASTER :
+ message = "was blasted by";
+ break;
+ case MOD_SHOTGUN :
+ message = "was gunned down by";
+ break;
+ case MOD_SSHOTGUN :
+ message = "was blown away by";
+ message2 = "'s super shotgun";
+ break;
+ case MOD_MACHINEGUN :
+ message = "was machinegunned by";
+ break;
+ case MOD_CHAINGUN :
+ message = "was cut in half by";
+ message2 = "'s chaingun";
+ break;
+ case MOD_GRENADE :
+ message = "was popped by";
+ message2 = "'s grenade";
+ break;
+ case MOD_G_SPLASH :
+ message = "was shredded by";
+ message2 = "'s shrapnel";
+ break;
+ case MOD_ROCKET :
+ message = "ate";
+ message2 = "'s rocket";
+ break;
+ case MOD_R_SPLASH :
+ message = "almost dodged";
+ message2 = "'s rocket";
+ break;
+ case MOD_HYPERBLASTER :
+ message = "was melted by";
+ message2 = "'s hyperblaster";
+ break;
+ case MOD_RAILGUN :
+ message = "was railed by";
+ break;
+ case MOD_BFG_LASER :
+ message = "saw the pretty lights from";
+ message2 = "'s BFG";
+ break;
+ case MOD_BFG_BLAST :
+ message = "was disintegrated by";
+ message2 = "'s BFG blast";
+ break;
+ case MOD_BFG_EFFECT :
+ message = "couldn't hide from";
+ message2 = "'s BFG";
+ break;
+ case MOD_HANDGRENADE :
+ message = "caught";
+ message2 = "'s handgrenade";
+ break;
+ case MOD_HG_SPLASH :
+ message = "didn't see";
+ message2 = "'s handgrenade";
+ break;
+ case MOD_HELD_GRENADE :
+ message = "feels";
+ message2 = "'s pain";
+ break;
+ case MOD_TELEFRAG :
+ message = "tried to invade";
+ message2 = "'s personal space";
+ break;
+ }
+ if (message != null) {
+ gi.bprintf(
+ PRINT_MEDIUM,
+ self.client.pers.netname + " " + message + " " + attacker.client.pers.netname + "" + message2);
+ if (deathmatch.value != 0) {
+ if (ff)
+ attacker.client.resp.score--;
+ else
+ attacker.client.resp.score++;
+ }
+ return;
+ }
+ }
+ }
+
+ gi.bprintf(PRINT_MEDIUM, self.client.pers.netname + " died.\n");
+ if (deathmatch.value != 0)
+ self.client.resp.score--;
+ }
+
+ /*
+ ==================
+ DeathmatchScoreboardMessage
+
+ ==================
+ */
+ public static void DeathmatchScoreboardMessage(edict_t ent, edict_t killer) {
+ String entry;
+ String string;
+ int stringlength;
+ int i, j, k;
+ int sorted[] = new int[MAX_CLIENTS];
+ int sortedscores[] = new int[MAX_CLIENTS];
+ int score, total;
+ int picnum;
+ int x, y;
+ gclient_t cl;
+ edict_t cl_ent;
+ String tag;
+
+ // sort the clients by score
+ total = 0;
+ for (i = 0; i < game.maxclients; i++) {
+ cl_ent = g_edicts[1 + i];
+ if (!cl_ent.inuse || game.clients[i].resp.spectator)
+ continue;
+ score = game.clients[i].resp.score;
+ for (j = 0; j < total; j++) {
+ if (score > sortedscores[j])
+ break;
+ }
+ for (k = total; k > j; k--) {
+ sorted[k] = sorted[k - 1];
+ sortedscores[k] = sortedscores[k - 1];
+ }
+ sorted[j] = i;
+ sortedscores[j] = score;
+ total++;
+ }
+
+ // print level name and exit rules
+ string = "";
+
+ stringlength = Lib.strlen(string);
+
+ // add the clients in sorted order
+ if (total > 12)
+ total = 12;
+
+ for (i = 0; i < total; i++) {
+ cl = game.clients[sorted[i]];
+ cl_ent = g_edicts[1 + sorted[i]];
+
+ picnum = gi.imageindex("i_fixme");
+ x = (i >= 6) ? 160 : 0;
+ y = 32 + 32 * (i % 6);
+
+ // add a dogtag
+ if (cl_ent == ent)
+ tag = "tag1";
+ else if (cl_ent == killer)
+ tag = "tag2";
+ else
+ tag = null;
+ if (tag != null) {
+ entry = "xv " + (x + 32) + " yv " + y + " picn " + tag + " ";
+ j = Lib.strlen(entry);
+ if (stringlength + j > 1024)
+ break;
+
+ string = string + entry;
+
+ //was: strcpy (string + stringlength, entry);
+ stringlength += j;
+ }
+
+ // send the layout
+ entry =
+ "client "
+ + x
+ + " "
+ + y
+ + " "
+ + sorted[i]
+ + " "
+ + cl.resp.score
+ + " "
+ + cl.ping
+ + " "
+ + (level.framenum - cl.resp.enterframe) / 600f
+ + " ";
+
+ j = Lib.strlen(entry);
+
+ if (stringlength + j > 1024)
+ break;
+
+ string += entry;
+ // was: strcpy(string + stringlength, entry);
+ stringlength += j;
+ }
+
+ gi.WriteByte(svc_layout);
+ gi.WriteString(string);
+ }
+
+ /*
+ ==================
+ DeathmatchScoreboard
+
+ Draw instead of help message.
+ Note that it isn't that hard to overflow the 1400 byte message limit!
+ ==================
+ */
+ public static void DeathmatchScoreboard(edict_t ent) {
+ DeathmatchScoreboardMessage(ent, ent.enemy);
+ gi.unicast(ent, true);
+ }
+
+ /*
+ ==================
+ HelpComputer
+
+ Draw help computer.
+ ==================
+ */
+ public static void HelpComputer(edict_t ent) {
+ String string;
+ String sk;
+
+ if (skill.value == 0)
+ sk = "easy";
+ else if (skill.value == 1)
+ sk = "medium";
+ else if (skill.value == 2)
+ sk = "hard";
+ else
+ sk = "hard+";
+
+ // send the layout
+ string = "xv 32 yv 8 picn help " + // background
+ "xv 202 yv 12 string2 \"" + sk + "\" " + // skill
+ "xv 0 yv 24 cstring2 \"" + level.level_name + "\" " + // level name
+ "xv 0 yv 54 cstring2 \"" + game.helpmessage1 + "\" " + // help 1
+ "xv 0 yv 110 cstring2 \"" + game.helpmessage2 + "\" " + // help 2
+ "xv 50 yv 164 string2 \" kills goals secrets\" "
+ + "xv 50 yv 172 string2 \""
+ + level.killed_monsters
+ + "/"
+ + level.total_monsters
+ + " "
+ + level.found_goals
+ + "/"
+ + level.total_goals
+ + " "
+ + level.found_secrets
+ + "/"
+ + level.total_secrets
+ + "\" ";
+
+ gi.WriteByte(svc_layout);
+ gi.WriteString(string);
+ gi.unicast(ent, true);
+ }
+
+ public static int player_die_i = 0;
+
+ /*
+ ==================
+ player_die
+ ==================
+ */
+ static EntDieAdapter player_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ Math3D.VectorClear(self.avelocity);
+
+ self.takedamage = DAMAGE_YES;
+ self.movetype = MOVETYPE_TOSS;
+
+ self.s.modelindex2 = 0; // remove linked weapon model
+
+ self.s.angles[0] = 0;
+ self.s.angles[2] = 0;
+
+ self.s.sound = 0;
+ self.client.weapon_sound = 0;
+
+ self.maxs[2] = -8;
+
+ // self.solid = SOLID_NOT;
+ self.svflags |= SVF_DEADMONSTER;
+
+ if (self.deadflag == 0) {
+ self.client.respawn_time = level.time + 1.0f;
+ LookAtKiller(self, inflictor, attacker);
+ self.client.ps.pmove.pm_type = PM_DEAD;
+ ClientObituary(self, inflictor, attacker);
+ TossClientWeapon(self);
+ if (deathmatch.value != 0)
+ Cmd.Help_f(self); // show scores
+
+ // clear inventory
+ // this is kind of ugly, but it's how we want to handle keys in coop
+ for (n = 0; n < game.num_items; n++) {
+ if (coop.value != 0 && (itemlist[n].flags & IT_KEY) != 0)
+ self.client.resp.coop_respawn.inventory[n] = self.client.pers.inventory[n];
+ self.client.pers.inventory[n] = 0;
+ }
+ }
+
+ // remove powerups
+ self.client.quad_framenum = 0;
+ self.client.invincible_framenum = 0;
+ self.client.breather_framenum = 0;
+ self.client.enviro_framenum = 0;
+ self.flags &= ~FL_POWER_ARMOR;
+
+ if (self.health < -40) { // gib
+ gi.sound(self, CHAN_BODY, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowClientHead(self, damage);
+
+ self.takedamage = DAMAGE_NO;
+ }
+ else { // normal death
+ if (self.deadflag == 0) {
+
+ player_die_i = (player_die_i + 1) % 3;
+ // start a death animation
+ self.client.anim_priority = ANIM_DEATH;
+ if ((self.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ self.s.frame = M_Player.FRAME_crdeath1 - 1;
+ self.client.anim_end = M_Player.FRAME_crdeath5;
+ }
+ else
+ switch (player_die_i) {
+ case 0 :
+ self.s.frame = M_Player.FRAME_death101 - 1;
+ self.client.anim_end = M_Player.FRAME_death106;
+ break;
+ case 1 :
+ self.s.frame = M_Player.FRAME_death201 - 1;
+ self.client.anim_end = M_Player.FRAME_death206;
+ break;
+ case 2 :
+ self.s.frame = M_Player.FRAME_death301 - 1;
+ self.client.anim_end = M_Player.FRAME_death308;
+ break;
+ }
+
+ gi.sound(self, CHAN_VOICE, gi.soundindex("*death" + ((Lib.rand() % 4) + 1) + ".wav"), 1, ATTN_NORM, 0);
+ }
+ }
+
+ self.deadflag = DEAD_DEAD;
+
+ gi.linkentity(self);
+ }
+ };
+
+ public static Comparator PlayerSort = new Comparator() {
+ public int compare(Object o1, Object o2) {
+ int anum = ((Integer) o1).intValue();
+ int bnum = ((Integer) o2).intValue();
+
+ int anum1 = game.clients[anum].ps.stats[STAT_FRAGS];
+ int bnum1 = game.clients[bnum].ps.stats[STAT_FRAGS];
+
+ if (anum1 < bnum1)
+ return -1;
+ if (anum1 > bnum1)
+ return 1;
+ return 0;
+ }
+ };
+
+ /**
+ * Processes the commands the player enters in the quake console.
+ *
+ */
+ public static void ClientCommand(edict_t ent) {
+ String cmd;
+
+ if (ent.client == null)
+ return; // not fully in game yet
+
+ cmd = gi.argv(0);
+
+ if (Lib.Q_stricmp(cmd, "players") == 0) {
+ Cmd.Players_f(ent);
+ return;
+ }
+ if (Lib.Q_stricmp(cmd, "say") == 0) {
+ Cmd.Say_f(ent, false, false);
+ return;
+ }
+ if (Lib.Q_stricmp(cmd, "say_team") == 0) {
+ Cmd.Say_f(ent, true, false);
+ return;
+ }
+ if (Lib.Q_stricmp(cmd, "score") == 0) {
+ Cmd.Score_f(ent);
+ return;
+ }
+ if (Lib.Q_stricmp(cmd, "help") == 0) {
+ Cmd.Help_f(ent);
+ return;
+ }
+
+ if (level.intermissiontime != 0)
+ return;
+
+ if (Lib.Q_stricmp(cmd, "use") == 0)
+ Cmd.Use_f(ent);
+ else if (Lib.Q_stricmp(cmd, "drop") == 0)
+ Cmd.Drop_f(ent);
+ else if (Lib.Q_stricmp(cmd, "give") == 0)
+ Cmd.Give_f(ent);
+ else if (Lib.Q_stricmp(cmd, "god") == 0)
+ Cmd.God_f(ent);
+ else if (Lib.Q_stricmp(cmd, "notarget") == 0)
+ Cmd.Notarget_f(ent);
+ else if (Lib.Q_stricmp(cmd, "noclip") == 0)
+ Cmd.Noclip_f(ent);
+ else if (Lib.Q_stricmp(cmd, "inven") == 0)
+ Cmd.Inven_f(ent);
+ else if (Lib.Q_stricmp(cmd, "invnext") == 0)
+ SelectNextItem(ent, -1);
+ else if (Lib.Q_stricmp(cmd, "invprev") == 0)
+ SelectPrevItem(ent, -1);
+ else if (Lib.Q_stricmp(cmd, "invnextw") == 0)
+ SelectNextItem(ent, IT_WEAPON);
+ else if (Lib.Q_stricmp(cmd, "invprevw") == 0)
+ SelectPrevItem(ent, IT_WEAPON);
+ else if (Lib.Q_stricmp(cmd, "invnextp") == 0)
+ SelectNextItem(ent, IT_POWERUP);
+ else if (Lib.Q_stricmp(cmd, "invprevp") == 0)
+ SelectPrevItem(ent, IT_POWERUP);
+ else if (Lib.Q_stricmp(cmd, "invuse") == 0)
+ Cmd.InvUse_f(ent);
+ else if (Lib.Q_stricmp(cmd, "invdrop") == 0)
+ Cmd.InvDrop_f(ent);
+ else if (Lib.Q_stricmp(cmd, "weapprev") == 0)
+ Cmd.WeapPrev_f(ent);
+ else if (Lib.Q_stricmp(cmd, "weapnext") == 0)
+ Cmd.WeapNext_f(ent);
+ else if (Lib.Q_stricmp(cmd, "weaplast") == 0)
+ Cmd.WeapLast_f(ent);
+ else if (Lib.Q_stricmp(cmd, "kill") == 0)
+ Cmd.Kill_f(ent);
+ else if (Lib.Q_stricmp(cmd, "putaway") == 0)
+ Cmd.PutAway_f(ent);
+ else if (Lib.Q_stricmp(cmd, "wave") == 0)
+ Cmd.Wave_f(ent);
+ else if (Lib.Q_stricmp(cmd, "playerlist") == 0)
+ Cmd.PlayerList_f(ent);
+ else // anything that doesn't match a command will be a chat
+ Cmd.Say_f(ent, false, true);
+ }
+
+ public static ItemUseAdapter Use_PowerArmor = new ItemUseAdapter() {
+ public void use(edict_t ent, gitem_t item) {
+ int index;
+
+ if ((ent.flags & FL_POWER_ARMOR) != 0) {
+ ent.flags &= ~FL_POWER_ARMOR;
+ gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
+ }
+ else {
+ index = ITEM_INDEX(FindItem("cells"));
+ if (0 == ent.client.pers.inventory[index]) {
+ gi.cprintf(ent, PRINT_HIGH, "No cells for power armor.\n");
+ return;
+ }
+ ent.flags |= FL_POWER_ARMOR;
+ gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_NORM, 0);
+ }
+ }
+ };
+
+ public static boolean Pickup_PowerArmor(edict_t ent, edict_t other) {
+ int quantity;
+
+ quantity = other.client.pers.inventory[ITEM_INDEX(ent.item)];
+
+ other.client.pers.inventory[ITEM_INDEX(ent.item)]++;
+
+ if (deathmatch.value != 0) {
+ if (0 == (ent.spawnflags & DROPPED_ITEM))
+ SetRespawn(ent, ent.item.quantity);
+ // auto-use for DM only if we didn't already have one
+ if (0 == quantity)
+ ent.item.use.use(other, ent.item);
+ }
+
+ return true;
+ }
+
+ public static ItemDropAdapter Drop_Ammo = new ItemDropAdapter() {
+ public void drop(edict_t ent, gitem_t item) {
+ edict_t dropped;
+ int index;
+
+ index = ITEM_INDEX(item);
+ dropped = Drop_Item(ent, item);
+ if (ent.client.pers.inventory[index] >= item.quantity)
+ dropped.count = item.quantity;
+ else
+ dropped.count = ent.client.pers.inventory[index];
+
+ if (ent.client.pers.weapon != null
+ && ent.client.pers.weapon.tag == AMMO_GRENADES
+ && item.tag == AMMO_GRENADES
+ && ent.client.pers.inventory[index] - dropped.count <= 0) {
+ gi.cprintf(ent, PRINT_HIGH, "Can't drop current weapon\n");
+ G_FreeEdict(dropped);
+ return;
+ }
+
+ ent.client.pers.inventory[index] -= dropped.count;
+ ValidateSelectedItem(ent);
+ }
+ };
+
+ public static ItemDropAdapter Drop_General = new ItemDropAdapter() {
+ public void drop(edict_t ent, gitem_t item) {
+ Drop_Item(ent, item);
+ ent.client.pers.inventory[ITEM_INDEX(item)]--;
+ ValidateSelectedItem(ent);
+ }
+ };
+
+ public static ItemDropAdapter Drop_PowerArmor = new ItemDropAdapter() {
+ public void drop(edict_t ent, gitem_t item) {
+ if (0 != (ent.flags & FL_POWER_ARMOR) && (ent.client.pers.inventory[ITEM_INDEX(item)] == 1))
+ Use_PowerArmor.use(ent, item);
+ Drop_General.drop(ent, item);
+ }
+ };
+
+ public static gitem_armor_t jacketarmor_info = new gitem_armor_t(25, 50, .30f, .00f, ARMOR_JACKET);
+ public static gitem_armor_t combatarmor_info = new gitem_armor_t(50, 100, .60f, .30f, ARMOR_COMBAT);
+ public static gitem_armor_t bodyarmor_info = new gitem_armor_t(100, 200, .80f, .60f, ARMOR_BODY);
+
+ public static gitem_t itemlist[] = {
+ //leave index 0 alone
+ null,
+
+ //
+ // ARMOR
+ //
+ new gitem_t(
+ /*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+
+ "item_armor_body", Pickup_Armor, null, null, null, "misc/ar1_pkup.wav", "models/items/armor/body/tris.md2", EF_ROTATE, null,
+ /* icon */
+ "i_bodyarmor",
+ /* pickup */
+ "Body Armor",
+ /* width */
+ 3, 0, null, IT_ARMOR, 0, bodyarmor_info, ARMOR_BODY,
+ /* precache */
+ ""),
+
+ /*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_armor_combat",
+ GameAI.Pickup_Armor,
+ null,
+ null,
+ null,
+ "misc/ar1_pkup.wav",
+ "models/items/armor/combat/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_combatarmor",
+ /* pickup */
+ "Combat Armor",
+ /* width */
+ 3, 0, null, IT_ARMOR, 0, GameAI.combatarmor_info, ARMOR_COMBAT,
+ /* precache */
+ ""),
+
+ /*QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_armor_jacket",
+ GameAI.Pickup_Armor,
+ null,
+ null,
+ null,
+ "misc/ar1_pkup.wav",
+ "models/items/armor/jacket/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_jacketarmor",
+ /* pickup */
+ "Jacket Armor",
+ /* width */
+ 3, 0, null, IT_ARMOR, 0, GameAI.jacketarmor_info, ARMOR_JACKET,
+ /* precache */
+ ""),
+
+ /*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_armor_shard",
+ GameAI.Pickup_Armor,
+ null,
+ null,
+ null,
+ "misc/ar2_pkup.wav",
+ "models/items/armor/shard/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_jacketarmor",
+ /* pickup */
+ "Armor Shard",
+ /* width */
+ 3, 0, null, IT_ARMOR, 0, null, ARMOR_SHARD,
+ /* precache */
+ ""),
+
+ /*QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_power_screen",
+ GameAI.Pickup_PowerArmor,
+ GameAI.Use_PowerArmor,
+ GameAI.Drop_PowerArmor,
+ null,
+ "misc/ar3_pkup.wav",
+ "models/items/armor/screen/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_powerscreen",
+ /* pickup */
+ "Power Screen",
+ /* width */
+ 0, 60, null, IT_ARMOR, 0, null, 0,
+ /* precache */
+ ""),
+
+ /*QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_power_shield",
+ Pickup_PowerArmor,
+ Use_PowerArmor,
+ Drop_PowerArmor,
+ null,
+ "misc/ar3_pkup.wav",
+ "models/items/armor/shield/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_powershield",
+ /* pickup */
+ "Power Shield",
+ /* width */
+ 0, 60, null, IT_ARMOR, 0, null, 0,
+ /* precache */
+ "misc/power2.wav misc/power1.wav"),
+
+ //
+ // WEAPONS
+ //
+
+ /* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16)
+ always owned, never in the world
+ */
+ new gitem_t(
+ "weapon_blaster",
+ null,
+ GamePWeapon.Use_Weapon,
+ null,
+ GamePWeapon.Weapon_Blaster,
+ "misc/w_pkup.wav",
+ null,
+ 0,
+ "models/weapons/v_blast/tris.md2",
+ /* icon */
+ "w_blaster",
+ /* pickup */
+ "Blaster", 0, 0, null, IT_WEAPON | IT_STAY_COOP, WEAP_BLASTER, null, 0,
+ /* precache */
+ "weapons/blastf1a.wav misc/lasfly.wav"),
+
+ /*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_shotgun",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_Shotgun,
+ "misc/w_pkup.wav",
+ "models/weapons/g_shotg/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_shotg/tris.md2",
+ /* icon */
+ "w_shotgun",
+ /* pickup */
+ "Shotgun", 0, 1, "Shells", IT_WEAPON | IT_STAY_COOP, WEAP_SHOTGUN, null, 0,
+ /* precache */
+ "weapons/shotgf1b.wav weapons/shotgr1b.wav"),
+
+ /*QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_supershotgun",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_SuperShotgun,
+ "misc/w_pkup.wav",
+ "models/weapons/g_shotg2/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_shotg2/tris.md2",
+ /* icon */
+ "w_sshotgun",
+ /* pickup */
+ "Super Shotgun", 0, 2, "Shells", IT_WEAPON | IT_STAY_COOP, WEAP_SUPERSHOTGUN, null, 0,
+ /* precache */
+ "weapons/sshotf1b.wav"),
+
+ /*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_machinegun",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_Machinegun,
+ "misc/w_pkup.wav",
+ "models/weapons/g_machn/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_machn/tris.md2",
+ /* icon */
+ "w_machinegun",
+ /* pickup */
+ "Machinegun", 0, 1, "Bullets", IT_WEAPON | IT_STAY_COOP, WEAP_MACHINEGUN, null, 0,
+ /* precache */
+ "weapons/machgf1b.wav weapons/machgf2b.wav weapons/machgf3b.wav weapons/machgf4b.wav weapons/machgf5b.wav"),
+
+ /*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_chaingun",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_Chaingun,
+ "misc/w_pkup.wav",
+ "models/weapons/g_chain/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_chain/tris.md2",
+ /* icon */
+ "w_chaingun",
+ /* pickup */
+ "Chaingun", 0, 1, "Bullets", IT_WEAPON | IT_STAY_COOP, WEAP_CHAINGUN, null, 0,
+ /* precache */
+ "weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav` weapons/chngnd1a.wav"),
+
+ /*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "ammo_grenades",
+ Pickup_Ammo,
+ GamePWeapon.Use_Weapon,
+ Drop_Ammo,
+ GamePWeapon.Weapon_Grenade,
+ "misc/am_pkup.wav",
+ "models/items/ammo/grenades/medium/tris.md2",
+ 0,
+ "models/weapons/v_handgr/tris.md2",
+ /* icon */
+ "a_grenades",
+ /* pickup */
+ "Grenades",
+ /* width */
+ 3, 5, "grenades", IT_AMMO | IT_WEAPON, WEAP_GRENADES, null, AMMO_GRENADES,
+ /* precache */
+ "weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav "),
+
+ /*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_grenadelauncher",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_GrenadeLauncher,
+ "misc/w_pkup.wav",
+ "models/weapons/g_launch/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_launch/tris.md2",
+ /* icon */
+ "w_glauncher",
+ /* pickup */
+ "Grenade Launcher", 0, 1, "Grenades", IT_WEAPON | IT_STAY_COOP, WEAP_GRENADELAUNCHER, null, 0,
+ /* precache */
+ "models/objects/grenade/tris.md2 weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav"),
+
+ /*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_rocketlauncher",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_RocketLauncher,
+ "misc/w_pkup.wav",
+ "models/weapons/g_rocket/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_rocket/tris.md2",
+ /* icon */
+ "w_rlauncher",
+ /* pickup */
+ "Rocket Launcher", 0, 1, "Rockets", IT_WEAPON | IT_STAY_COOP, WEAP_ROCKETLAUNCHER, null, 0,
+ /* precache */
+ "models/objects/rocket/tris.md2 weapons/rockfly.wav weapons/rocklf1a.wav weapons/rocklr1b.wav models/objects/debris2/tris.md2"),
+
+ /*QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_hyperblaster",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_HyperBlaster,
+ "misc/w_pkup.wav",
+ "models/weapons/g_hyperb/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_hyperb/tris.md2",
+ /* icon */
+ "w_hyperblaster",
+ /* pickup */
+ "HyperBlaster", 0, 1, "Cells", IT_WEAPON | IT_STAY_COOP, WEAP_HYPERBLASTER, null, 0,
+ /* precache */
+ "weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav"),
+
+ /*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_railgun",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_Railgun,
+ "misc/w_pkup.wav",
+ "models/weapons/g_rail/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_rail/tris.md2",
+ /* icon */
+ "w_railgun",
+ /* pickup */
+ "Railgun", 0, 1, "Slugs", IT_WEAPON | IT_STAY_COOP, WEAP_RAILGUN, null, 0,
+ /* precache */
+ "weapons/rg_hum.wav"),
+
+ /*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "weapon_bfg",
+ GamePWeapon.Pickup_Weapon,
+ GamePWeapon.Use_Weapon,
+ GamePWeapon.Drop_Weapon,
+ GamePWeapon.Weapon_BFG,
+ "misc/w_pkup.wav",
+ "models/weapons/g_bfg/tris.md2",
+ EF_ROTATE,
+ "models/weapons/v_bfg/tris.md2",
+ /* icon */
+ "w_bfg",
+ /* pickup */
+ "BFG10K", 0, 50, "Cells", IT_WEAPON | IT_STAY_COOP, WEAP_BFG, null, 0,
+ /* precache */
+ "sprites/s_bfg1.sp2 sprites/s_bfg2.sp2 sprites/s_bfg3.sp2 weapons/bfg__f1y.wav weapons/bfg__l1a.wav weapons/bfg__x1b.wav weapons/bfg_hum.wav"),
+
+ //
+ // AMMO ITEMS
+ //
+
+ /*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "ammo_shells",
+ GamePWeapon.Pickup_Ammo,
+ null,
+ GamePWeapon.Drop_Ammo,
+ null,
+ "misc/am_pkup.wav",
+ "models/items/ammo/shells/medium/tris.md2",
+ 0,
+ null,
+ /* icon */
+ "a_shells",
+ /* pickup */
+ "Shells",
+ /* width */
+ 3, 10, null, IT_AMMO, 0, null, AMMO_SHELLS,
+ /* precache */
+ ""),
+
+ /*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "ammo_bullets",
+ GamePWeapon.Pickup_Ammo,
+ null,
+ GamePWeapon.Drop_Ammo,
+ null,
+ "misc/am_pkup.wav",
+ "models/items/ammo/bullets/medium/tris.md2",
+ 0,
+ null,
+ /* icon */
+ "a_bullets",
+ /* pickup */
+ "Bullets",
+ /* width */
+ 3, 50, null, IT_AMMO, 0, null, AMMO_BULLETS,
+ /* precache */
+ ""),
+
+ /*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "ammo_cells",
+ GamePWeapon.Pickup_Ammo,
+ null,
+ GamePWeapon.Drop_Ammo,
+ null,
+ "misc/am_pkup.wav",
+ "models/items/ammo/cells/medium/tris.md2",
+ 0,
+ null,
+ /* icon */
+ "a_cells",
+ /* pickup */
+ "Cells",
+ /* width */
+ 3, 50, null, IT_AMMO, 0, null, AMMO_CELLS,
+ /* precache */
+ ""),
+
+ /*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "ammo_rockets",
+ GamePWeapon.Pickup_Ammo,
+ null,
+ GamePWeapon.Drop_Ammo,
+ null,
+ "misc/am_pkup.wav",
+ "models/items/ammo/rockets/medium/tris.md2",
+ 0,
+ null,
+ /* icon */
+ "a_rockets",
+ /* pickup */
+ "Rockets",
+ /* width */
+ 3, 5, null, IT_AMMO, 0, null, AMMO_ROCKETS,
+ /* precache */
+ ""),
+
+ /*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "ammo_slugs",
+ GamePWeapon.Pickup_Ammo,
+ null,
+ GamePWeapon.Drop_Ammo,
+ null,
+ "misc/am_pkup.wav",
+ "models/items/ammo/slugs/medium/tris.md2",
+ 0,
+ null,
+ /* icon */
+ "a_slugs",
+ /* pickup */
+ "Slugs",
+ /* width */
+ 3, 10, null, IT_AMMO, 0, null, AMMO_SLUGS,
+ /* precache */
+ ""),
+
+ //
+ // POWERUP ITEMS
+ //
+ /*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_quad",
+ Pickup_Powerup,
+ Use_Quad,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/quaddama/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "p_quad",
+ /* pickup */
+ "Quad Damage",
+ /* width */
+ 2, 60, null, IT_POWERUP, 0, null, 0,
+ /* precache */
+ "items/damage.wav items/damage2.wav items/damage3.wav"),
+
+ /*QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_invulnerability",
+ Pickup_Powerup,
+ Use_Invulnerability,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/invulner/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "p_invulnerability",
+ /* pickup */
+ "Invulnerability",
+ /* width */
+ 2, 300, null, IT_POWERUP, 0, null, 0,
+ /* precache */
+ "items/protect.wav items/protect2.wav items/protect4.wav"),
+
+ /*QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_silencer",
+ Pickup_Powerup,
+ Use_Silencer,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/silencer/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "p_silencer",
+ /* pickup */
+ "Silencer",
+ /* width */
+ 2, 60, null, IT_POWERUP, 0, null, 0,
+ /* precache */
+ ""),
+
+ /*QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_breather",
+ Pickup_Powerup,
+ Use_Breather,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/breather/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "p_rebreather",
+ /* pickup */
+ "Rebreather",
+ /* width */
+ 2, 60, null, IT_STAY_COOP | IT_POWERUP, 0, null, 0,
+ /* precache */
+ "items/airout.wav"),
+
+ /*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_enviro",
+ Pickup_Powerup,
+ Use_Envirosuit,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/enviro/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "p_envirosuit",
+ /* pickup */
+ "Environment Suit",
+ /* width */
+ 2, 60, null, IT_STAY_COOP | IT_POWERUP, 0, null, 0,
+ /* precache */
+ "items/airout.wav"),
+
+ /*QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16)
+ Special item that gives +2 to maximum health
+ */
+ new gitem_t(
+ "item_ancient_head",
+ Pickup_AncientHead,
+ null,
+ null,
+ null,
+ "items/pkup.wav",
+ "models/items/c_head/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_fixme",
+ /* pickup */
+ "Ancient Head",
+ /* width */
+ 2, 60, null, 0, 0, null, 0,
+ /* precache */
+ ""),
+
+ /*QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16)
+ gives +1 to maximum health
+ */
+ new gitem_t(
+ "item_adrenaline",
+ Pickup_Adrenaline,
+ null,
+ null,
+ null,
+ "items/pkup.wav",
+ "models/items/adrenal/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "p_adrenaline",
+ /* pickup */
+ "Adrenaline",
+ /* width */
+ 2, 60, null, 0, 0, null, 0,
+ /* precache */
+ ""),
+
+ /*QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_bandolier",
+ Pickup_Bandolier,
+ null,
+ null,
+ null,
+ "items/pkup.wav",
+ "models/items/band/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "p_bandolier",
+ /* pickup */
+ "Bandolier",
+ /* width */
+ 2, 60, null, 0, 0, null, 0,
+ /* precache */
+ ""),
+
+ /*QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ new gitem_t(
+ "item_pack",
+ GamePWeapon.Pickup_Pack,
+ null,
+ null,
+ null,
+ "items/pkup.wav",
+ "models/items/pack/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_pack",
+ /* pickup */
+ "Ammo Pack",
+ /* width */
+ 2, 180, null, 0, 0, null, 0,
+ /* precache */
+ ""),
+
+ //
+ // KEYS
+ //
+ /*QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16)
+ key for computer centers
+ */
+ new gitem_t(
+ "key_data_cd",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/data_cd/tris.md2",
+ EF_ROTATE,
+ null,
+ "k_datacd",
+ "Data CD",
+ 2,
+ 0,
+ null,
+ IT_STAY_COOP | IT_KEY,
+ 0,
+ null,
+ 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_power_cube (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN NO_TOUCH
+ warehouse circuits
+ */
+ new gitem_t(
+ "key_power_cube",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/power/tris.md2",
+ EF_ROTATE,
+ null,
+ "k_powercube",
+ "Power Cube",
+ 2,
+ 0,
+ null,
+ IT_STAY_COOP | IT_KEY,
+ 0,
+ null,
+ 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16)
+ key for the entrance of jail3
+ */
+ new gitem_t(
+ "key_pyramid",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/pyramid/tris.md2",
+ EF_ROTATE,
+ null,
+ "k_pyramid",
+ "Pyramid Key",
+ 2,
+ 0,
+ null,
+ IT_STAY_COOP | IT_KEY,
+ 0,
+ null,
+ 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16)
+ key for the city computer
+ */
+ new gitem_t(
+ "key_data_spinner",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/spinner/tris.md2",
+ EF_ROTATE,
+ null,
+ "k_dataspin",
+ "Data Spinner",
+ 2,
+ 0,
+ null,
+ IT_STAY_COOP | IT_KEY,
+ 0,
+ null,
+ 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16)
+ security pass for the security level
+ */
+ new gitem_t(
+ "key_pass",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/pass/tris.md2",
+ EF_ROTATE,
+ null,
+ "k_security",
+ "Security Pass",
+ 2,
+ 0,
+ null,
+ IT_STAY_COOP | IT_KEY,
+ 0,
+ null,
+ 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16)
+ normal door key - blue
+ */
+ new gitem_t(
+ "key_blue_key",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/key/tris.md2",
+ EF_ROTATE,
+ null,
+ "k_bluekey",
+ "Blue Key",
+ 2,
+ 0,
+ null,
+ IT_STAY_COOP | IT_KEY,
+ 0,
+ null,
+ 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16)
+ normal door key - red
+ */
+ new gitem_t(
+ "key_red_key",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/red_key/tris.md2",
+ EF_ROTATE,
+ null,
+ "k_redkey",
+ "Red Key",
+ 2,
+ 0,
+ null,
+ IT_STAY_COOP | IT_KEY,
+ 0,
+ null,
+ 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16)
+ tank commander's head
+ */
+ new gitem_t(
+ "key_commander_head",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/monsters/commandr/head/tris.md2",
+ EF_GIB,
+ null,
+ /* icon */
+ "k_comhead",
+ /* pickup */
+ "Commander's Head",
+ /* width */
+ 2, 0, null, IT_STAY_COOP | IT_KEY, 0, null, 0,
+ /* precache */
+ ""),
+
+ /*QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16)
+ tank commander's head
+ */
+ new gitem_t(
+ "key_airstrike_target",
+ Pickup_Key,
+ null,
+ Drop_General,
+ null,
+ "items/pkup.wav",
+ "models/items/keys/target/tris.md2",
+ EF_ROTATE,
+ null,
+ /* icon */
+ "i_airstrike",
+ /* pickup */
+ "Airstrike Marker",
+ /* width */
+ 2, 0, null, IT_STAY_COOP | IT_KEY, 0, null, 0,
+ /* precache */
+ ""), new gitem_t(null, Pickup_Health, null, null, null, "items/pkup.wav", null, 0, null,
+ /* icon */
+ "i_health",
+ /* pickup */
+ "Health",
+ /* width */
+ 3, 0, null, 0, 0, null, 0,
+ /* precache */
+ "items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav"),
+
+ // end of list marker
+ null };
+
+ public static void InitItems() {
+ //game.num_items = sizeof(itemlist)/sizeof(itemlist[0]) - 1;
+ game.num_items = itemlist.length - 1;
+ }
+
+
+
+ /*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ public static void SP_item_health (edict_t self)
+ {
+ if ( deathmatch.value!=0 && ((int)dmflags.value & DF_NO_HEALTH) !=0)
+ {
+ G_FreeEdict (self);
+ }
+
+ self.model = "models/items/healing/medium/tris.md2";
+ self.count = 10;
+ SpawnItem (self, FindItem ("Health"));
+ gi.soundindex ("items/n_health.wav");
+ }
+
+ /*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ static void SP_item_health_small (edict_t self)
+ {
+ if ( deathmatch.value!=0 && ((int)dmflags.value & DF_NO_HEALTH)!=0)
+ {
+ G_FreeEdict (self);
+ return;
+ }
+
+ self.model = "models/items/healing/stimpack/tris.md2";
+ self.count = 2;
+ SpawnItem (self, FindItem ("Health"));
+ self.style = HEALTH_IGNORE_MAX;
+ gi.soundindex ("items/s_health.wav");
+ }
+
+ /*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ static void SP_item_health_large (edict_t self)
+ {
+ if ( deathmatch.value!=0 && ((int)dmflags.value & DF_NO_HEALTH) !=0)
+ {
+ G_FreeEdict (self);
+ return;
+ }
+
+ self.model = "models/items/healing/large/tris.md2";
+ self.count = 25;
+ SpawnItem (self, FindItem ("Health"));
+ gi.soundindex ("items/l_health.wav");
+ }
+
+ /*
+ * QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16)
+ */
+ static void SP_item_health_mega (edict_t self)
+ {
+ if ( deathmatch.value!=0 && ((int)dmflags.value & DF_NO_HEALTH) !=0)
+ {
+ G_FreeEdict (self);
+ return;
+ }
+
+ self.model = "models/items/mega_h/tris.md2";
+ self.count = 100;
+ SpawnItem (self, FindItem ("Health"));
+ gi.soundindex ("items/m_health.wav");
+ self.style = HEALTH_IGNORE_MAX | HEALTH_TIMED;
+ }
+}
diff --git a/src/jake2/game/GameBase.java b/src/jake2/game/GameBase.java
new file mode 100644
index 0000000..317da9b
--- /dev/null
+++ b/src/jake2/game/GameBase.java
@@ -0,0 +1,824 @@
+/*
+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 30.11.2003 by RST.
+// $Id: GameBase.java,v 1.1 2004-07-07 19:58:56 hzi Exp $
+
+/** Father of all Objects. */
+
+package jake2.game;
+
+import java.util.StringTokenizer;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.Com;
+import jake2.server.*;
+import jake2.util.*;
+
+public class GameBase extends Globals {
+ public static game_locals_t game = new game_locals_t();
+ public static level_locals_t level = new level_locals_t();
+ public static game_import_t gi = new game_import_t();
+ public static game_export_t globals = new game_export_t();
+ public static spawn_temp_t st = new spawn_temp_t();
+
+ public static int sm_meat_index;
+ public static int snd_fry;
+ public static int meansOfDeath;
+
+ public static edict_t g_edicts[] = new edict_t[MAX_EDICTS];
+ static {
+ for (int n = 0; n < MAX_EDICTS; n++)
+ g_edicts[n] = new edict_t(n);
+ }
+
+ public static cvar_t deathmatch = new cvar_t();
+ public static cvar_t coop = new cvar_t();
+ public static cvar_t dmflags = new cvar_t();
+ public static cvar_t skill; // = new cvar_t();
+ public static cvar_t fraglimit = new cvar_t();
+ public static cvar_t timelimit = new cvar_t();
+ public static cvar_t password = new cvar_t();
+ public static cvar_t spectator_password = new cvar_t();
+ public static cvar_t needpass = new cvar_t();
+ public static cvar_t maxclients = new cvar_t();
+ public static cvar_t maxspectators = new cvar_t();
+ public static cvar_t maxentities = new cvar_t();
+ public static cvar_t g_select_empty = new cvar_t();
+ public static cvar_t dedicated = new cvar_t();
+
+ public static cvar_t filterban = new cvar_t();
+
+ public static cvar_t sv_maxvelocity = new cvar_t();
+ public static cvar_t sv_gravity = new cvar_t();
+
+ public static cvar_t sv_rollspeed = new cvar_t();
+ public static cvar_t sv_rollangle = new cvar_t();
+ public static cvar_t gun_x = new cvar_t();
+ public static cvar_t gun_y = new cvar_t();
+ public static cvar_t gun_z = new cvar_t();
+
+ public static cvar_t run_pitch = new cvar_t();
+ public static cvar_t run_roll = new cvar_t();
+ public static cvar_t bob_up = new cvar_t();
+ public static cvar_t bob_pitch = new cvar_t();
+ public static cvar_t bob_roll = new cvar_t();
+
+ public static cvar_t sv_cheats = new cvar_t();
+
+ public static cvar_t flood_msgs = new cvar_t();
+ public static cvar_t flood_persecond = new cvar_t();
+ public static cvar_t flood_waitdelay = new cvar_t();
+
+ public static cvar_t sv_maplist = new cvar_t();
+
+ public final static float STOP_EPSILON = 0.1f;
+
+ static field_t fields_ent[] =
+ new field_t[] {
+ new field_t("classname", F_LSTRING),
+ new field_t("model", F_LSTRING),
+ new field_t("spawnflags", F_INT),
+ new field_t("speed", F_FLOAT),
+ new field_t("accel", F_FLOAT),
+ new field_t("decel", F_FLOAT),
+ new field_t("target", F_LSTRING),
+ new field_t("targetname", F_LSTRING),
+ new field_t("pathtarget", F_LSTRING),
+ new field_t("deathtarget", F_LSTRING),
+ new field_t("killtarget", F_LSTRING),
+ new field_t("combattarget", F_LSTRING),
+ new field_t("message", F_LSTRING),
+ new field_t("team", F_LSTRING),
+ new field_t("wait", F_FLOAT),
+ new field_t("delay", F_FLOAT),
+ new field_t("random", F_FLOAT),
+ new field_t("move_origin", F_VECTOR),
+ new field_t("move_angles", F_VECTOR),
+ new field_t("style", F_INT),
+ new field_t("count", F_INT),
+ new field_t("health", F_INT),
+ new field_t("sounds", F_INT),
+ new field_t("light", F_IGNORE),
+ new field_t("dmg", F_INT),
+ new field_t("mass", F_INT),
+ new field_t("volume", F_FLOAT),
+ new field_t("attenuation", F_FLOAT),
+ new field_t("map", F_LSTRING),
+ new field_t("origin", F_VECTOR),
+ new field_t("angles", F_VECTOR),
+ new field_t("angle", F_ANGLEHACK),
+ new field_t("goalentity", F_EDICT, FFL_NOSPAWN),
+ new field_t("movetarget", F_EDICT, FFL_NOSPAWN),
+ new field_t("enemy", F_EDICT, FFL_NOSPAWN),
+ new field_t("oldenemy", F_EDICT, FFL_NOSPAWN),
+ new field_t("activator", F_EDICT, FFL_NOSPAWN),
+ new field_t("groundentity", F_EDICT, FFL_NOSPAWN),
+ new field_t("teamchain", F_EDICT, FFL_NOSPAWN),
+ new field_t("teammaster", F_EDICT, FFL_NOSPAWN),
+ new field_t("owner", F_EDICT, FFL_NOSPAWN),
+ new field_t("mynoise", F_EDICT, FFL_NOSPAWN),
+ new field_t("mynoise2", F_EDICT, FFL_NOSPAWN),
+ new field_t("target_ent", F_EDICT, FFL_NOSPAWN),
+ new field_t("chain", F_EDICT, FFL_NOSPAWN),
+ new field_t("prethink", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("think", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("blocked", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("touch", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("use", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("pain", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("die", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("stand", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("idle", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("search", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("walk", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("run", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("dodge", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("attack", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("melee", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("sight", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("checkattack", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("currentmove", F_MMOVE, FFL_NOSPAWN),
+ new field_t("endfunc", F_FUNCTION, FFL_NOSPAWN),
+ new field_t("item", F_ITEM)
+ //need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves
+ };
+
+ // temp spawn vars -- only valid when the spawn function is called
+ static field_t fields_st[] =
+ {
+ new field_t("lip", F_INT, FFL_SPAWNTEMP),
+ new field_t("distance", F_INT, FFL_SPAWNTEMP),
+ new field_t("height", F_INT, FFL_SPAWNTEMP),
+ new field_t("noise", F_LSTRING, FFL_SPAWNTEMP),
+ new field_t("pausetime", F_FLOAT, FFL_SPAWNTEMP),
+ new field_t("item", F_LSTRING, FFL_SPAWNTEMP),
+ new field_t("gravity", F_LSTRING, FFL_SPAWNTEMP),
+ new field_t("sky", F_LSTRING, FFL_SPAWNTEMP),
+ new field_t("skyrotate", F_FLOAT, FFL_SPAWNTEMP),
+ new field_t("skyaxis", F_VECTOR, FFL_SPAWNTEMP),
+ new field_t("minyaw", F_FLOAT, FFL_SPAWNTEMP),
+ new field_t("maxyaw", F_FLOAT, FFL_SPAWNTEMP),
+ new field_t("minpitch", F_FLOAT, FFL_SPAWNTEMP),
+ new field_t("maxpitch", F_FLOAT, FFL_SPAWNTEMP),
+ new field_t("nextmap", F_LSTRING, FFL_SPAWNTEMP),
+ };
+
+ /**
+ * Slide off of the impacting object
+ * returns the blocked flags (1 = floor, 2 = step / wall).
+ */
+ public static int ClipVelocity(float[] in, float[] normal, float[] out, float overbounce) {
+ float backoff;
+ float change;
+ int i, blocked;
+
+ blocked = 0;
+ if (normal[2] > 0)
+ blocked |= 1; // floor
+ if (normal[2] == 0.0f)
+ blocked |= 2; // step
+
+ backoff = Math3D.DotProduct(in, normal) * overbounce;
+
+ for (i = 0; i < 3; i++) {
+ change = normal[i] * backoff;
+ out[i] = in[i] - change;
+ if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
+ out[i] = 0;
+ }
+
+ return blocked;
+ }
+
+ /**
+ SV_FlyMove
+
+ The basic solid body movement clip that slides along multiple planes
+ Returns the clipflags if the velocity was modified (hit something solid)
+ 1 = floor
+ 2 = wall / step
+ 4 = dead stop
+ */
+ public final static int MAX_CLIP_PLANES = 5;
+
+ /*
+ =============
+ G_Find
+
+ Searches all active entities for the next one that holds
+ the matching string at fieldofs (use the FOFS() macro) in the structure.
+
+ Searches beginning at the edict after from, or the beginning if null
+ null will be returned if the end of the list is reached.
+
+ =============
+ */
+
+ /**
+ * Finds an edict.
+ * Call with null as from parameter to search from array beginning.
+ */
+
+ public static EdictIterator G_Find(EdictIterator from, EdictFindFilter eff, String s) {
+
+ if (from == null)
+ from = new EdictIterator(0);
+ else
+ from.i++;
+
+ for (; from.i < globals.num_edicts; from.i++) {
+ from.o = g_edicts[from.i];
+ if (from.o.classname == null) {
+ Com.Printf("edict with classname = null" + from.o.index);
+ }
+
+ if (!from.o.inuse)
+ continue;
+
+ if (eff.matches(from.o, s))
+ return from;
+ }
+
+ return null;
+ }
+
+ // comfort version (rst)
+ public static edict_t G_FindEdict(EdictIterator from, EdictFindFilter eff, String s) {
+ EdictIterator ei = G_Find(from, eff, s);
+ if (ei == null)
+ return null;
+ else
+ return ei.o;
+ }
+
+ /**
+ * Returns entities that have origins within a spherical area.
+ */
+ public static EdictIterator findradius(EdictIterator from, float[] org, float rad) {
+ float[] eorg = { 0, 0, 0 };
+ int j;
+
+ if (from == null)
+ from = new EdictIterator(0);
+ else
+ from.i++;
+
+ for (; from.i < globals.num_edicts; from.i++) {
+ from.o = g_edicts[from.i];
+ if (!from.o.inuse)
+ continue;
+
+ if (from.o.solid == SOLID_NOT)
+ continue;
+
+ for (j = 0; j < 3; j++)
+ eorg[j] = org[j] - (from.o.s.origin[j] + (from.o.mins[j] + from.o.maxs[j]) * 0.5f);
+
+ if (Math3D.VectorLength(eorg) > rad)
+ continue;
+ return from;
+ }
+
+ return null;
+ }
+
+ /**
+ * Searches all active entities for the next one that holds
+ * the matching string at fieldofs (use the FOFS() macro) in the structure.
+ *
+ * Searches beginning at the edict after from, or the beginning if null
+ * null will be returned if the end of the list is reached.
+ */
+
+ public static int MAXCHOICES = 8;
+
+ public static edict_t G_PickTarget(String targetname) {
+ int num_choices = 0;
+ edict_t choice[] = new edict_t[MAXCHOICES];
+
+ if (targetname == null) {
+ gi.dprintf("G_PickTarget called with null targetname\n");
+ return null;
+ }
+
+ EdictIterator es = null;
+
+ while ((es = G_Find(es, findByTarget, targetname)) != null) {
+ choice[num_choices++] = es.o;
+ if (num_choices == MAXCHOICES)
+ break;
+ }
+
+ if (num_choices == 0) {
+ gi.dprintf("G_PickTarget: target " + targetname + " not found\n");
+ return null;
+ }
+
+ return choice[Lib.rand() % num_choices];
+ }
+
+ public static float[] VEC_UP = { 0, -1, 0 };
+ public static float[] MOVEDIR_UP = { 0, 0, 1 };
+ public static float[] VEC_DOWN = { 0, -2, 0 };
+ public static float[] MOVEDIR_DOWN = { 0, 0, -1 };
+
+ public static void G_SetMovedir(float[] angles, float[] movedir) {
+ if (Math3D.VectorCompare(angles, VEC_UP) != 0) {
+ Math3D.VectorCopy(MOVEDIR_UP, movedir);
+ }
+ else if (Math3D.VectorCompare(angles, VEC_DOWN) != 0) {
+ Math3D.VectorCopy(MOVEDIR_DOWN, movedir);
+ }
+ else {
+ Math3D.AngleVectors(angles, movedir, null, null);
+ }
+
+ Math3D.VectorClear(angles);
+ }
+
+ public static String G_CopyString(String in) {
+ return new String(in);
+ }
+
+ /*
+ ============
+ G_TouchTriggers
+
+ ============
+ */
+ public static void G_TouchTriggers(edict_t ent) {
+ int i, num;
+ edict_t touch[] = new edict_t[MAX_EDICTS], hit;
+
+ // dead things don't activate triggers!
+ if ((ent.client != null || (ent.svflags & SVF_MONSTER) != 0) && (ent.health <= 0))
+ return;
+
+ num = gi.BoxEdicts(ent.absmin, ent.absmax, touch, MAX_EDICTS, AREA_TRIGGERS);
+
+ // be careful, it is possible to have an entity in this
+ // list removed before we get to it (killtriggered)
+ for (i = 0; i < num; i++) {
+ hit = touch[i];
+ if (!hit.inuse)
+ continue;
+
+ if (hit.touch == null)
+ continue;
+
+ hit.touch.touch(hit, ent, null, null);
+ }
+ }
+
+ public static pushed_t pushed[] = new pushed_t[MAX_EDICTS];
+ public static int pushed_p;
+
+ public static edict_t obstacle;
+
+ /*
+ =============
+ M_CheckBottom
+
+ Returns false if any part of the bottom of the entity is off an edge that
+ is not a staircase.
+
+ =============
+ */
+ public static int c_yes, c_no;
+
+ public static int STEPSIZE = 18;
+
+ // ============================================================================
+ /*
+ ================
+ G_RunEntity
+
+ ================
+ */
+ public static void G_RunEntity(edict_t ent) {
+ if (ent.prethink != null)
+ ent.prethink.think(ent);
+
+ switch ((int) ent.movetype) {
+ case MOVETYPE_PUSH :
+ case MOVETYPE_STOP :
+ SV.SV_Physics_Pusher(ent);
+ break;
+ case MOVETYPE_NONE :
+ SV.SV_Physics_None(ent);
+ break;
+ case MOVETYPE_NOCLIP :
+ SV.SV_Physics_Noclip(ent);
+ break;
+ case MOVETYPE_STEP :
+ SV.SV_Physics_Step(ent);
+ break;
+ case MOVETYPE_TOSS :
+ case MOVETYPE_BOUNCE :
+ case MOVETYPE_FLY :
+ case MOVETYPE_FLYMISSILE :
+ SV.SV_Physics_Toss(ent);
+ break;
+ default :
+ gi.error("SV_Physics: bad movetype " + (int) ent.movetype);
+ }
+ }
+
+ /*
+ ================
+ SV_NewChaseDir
+
+ ================
+ */
+ public static int DI_NODIR = -1;
+ public static void assert1(boolean cond) {
+ if (!cond) {
+
+ try {
+
+ int a[] = null;
+ int b = a[0];
+ }
+ catch (Exception e) {
+ System.err.println("assertion failed!");
+ e.printStackTrace();
+ }
+
+ }
+ }
+
+ public static void ClearBounds(float[] mins, float[] maxs) {
+ mins[0] = mins[1] = mins[2] = 99999;
+ maxs[0] = maxs[1] = maxs[2] = -99999;
+ }
+
+ public static void AddPointToBounds(float[] v, float[] mins, float[] maxs) {
+ int i;
+ float val;
+
+ for (i = 0; i < 3; i++) {
+ val = v[i];
+ if (val < mins[i])
+ mins[i] = val;
+ if (val > maxs[i])
+ maxs[i] = val;
+ }
+ }
+
+ public static EdictFindFilter findByTarget = new EdictFindFilter() {
+ public boolean matches(edict_t e, String s) {
+ if (e.targetname == null)
+ return false;
+ return e.targetname.equalsIgnoreCase(s);
+ }
+ };
+
+ public static EdictFindFilter findByClass = new EdictFindFilter() {
+ public boolean matches(edict_t e, String s) {
+ return e.classname.equalsIgnoreCase(s);
+ }
+ };
+
+ //===================================================================
+
+ public static void ShutdownGame() {
+ gi.dprintf("==== ShutdownGame ====\n");
+
+ //gi.FreeTags (TAG_LEVEL);
+ //gi.FreeTags (TAG_GAME);
+ }
+
+ //======================================================================
+
+ /*
+ =================
+ ClientEndServerFrames
+ =================
+ */
+ public static void ClientEndServerFrames() {
+ int i;
+ edict_t ent;
+
+ // calc the player views now that all pushing
+ // and damage has been added
+ for (i = 0; i < maxclients.value; i++) {
+ ent = g_edicts[1 + i];
+ if (!ent.inuse || null == ent.client)
+ continue;
+ Game.ClientEndServerFrame(ent);
+ }
+
+ }
+
+ /*
+ =================
+ CreateTargetChangeLevel
+
+ Returns the created target changelevel
+ =================
+ */
+ public static edict_t CreateTargetChangeLevel(String map) {
+ edict_t ent;
+
+ ent = Game.G_Spawn();
+ ent.classname = "target_changelevel";
+ level.nextmap = map;
+ ent.map = level.nextmap;
+ return ent;
+ }
+
+ /*
+ =================
+ EndDMLevel
+
+ The timelimit or fraglimit has been exceeded
+ =================
+ */
+ public static void EndDMLevel() {
+ edict_t ent;
+ //char * s, * t, * f;
+ //static const char * seps = " ,\n\r";
+ String s, t, f;
+ String seps = " ,\n\r";
+
+ // stay on same level flag
+ if (((int) dmflags.value & DF_SAME_LEVEL) != 0) {
+ Game.BeginIntermission(CreateTargetChangeLevel(level.mapname));
+ return;
+ }
+
+ // see if it's in the map list
+ if (sv_maplist.string.length() > 0) {
+ s = sv_maplist.string;
+ f = null;
+ StringTokenizer tk = new StringTokenizer(s, seps);
+ t = tk.nextToken();
+ //t = strtok(s, seps);
+ while (t != null) {
+ if (Q_stricmp(t, level.mapname) == 0) {
+ // it's in the list, go to the next one
+ t = tk.nextToken();
+ if (t == null) { // end of list, go to first one
+ if (f == null) // there isn't a first one, same level
+ Game.BeginIntermission(CreateTargetChangeLevel(level.mapname));
+ else
+ Game.BeginIntermission(CreateTargetChangeLevel(f));
+ }
+ else
+ Game.BeginIntermission(CreateTargetChangeLevel(t));
+ return;
+ }
+ if (f == null)
+ f = t;
+ t = tk.nextToken();
+ }
+
+ }
+
+ if (level.nextmap.length() > 0) // go to a specific map
+ Game.BeginIntermission(CreateTargetChangeLevel(level.nextmap));
+ else { // search for a changelevel
+ EdictIterator edit = null;
+ edit = G_Find(edit, findByClass, "target_changelevel");
+ if (edit == null) { // the map designer didn't include a changelevel,
+ // so create a fake ent that goes back to the same level
+ Game.BeginIntermission(CreateTargetChangeLevel(level.mapname));
+ return;
+ }
+ ent = edit.o;
+ Game.BeginIntermission(ent);
+ }
+ }
+
+ /*
+ =================
+ CheckNeedPass
+ =================
+ */
+ public static void CheckNeedPass() {
+ int need;
+
+ // if password or spectator_password has changed, update needpass
+ // as needed
+ if (password.modified || spectator_password.modified) {
+ password.modified = spectator_password.modified = false;
+
+ need = 0;
+
+ if ((password.string.length() > 0) && 0 != Q_stricmp(password.string, "none"))
+ need |= 1;
+ if ((spectator_password.string.length() > 0) && 0 != Q_stricmp(spectator_password.string, "none"))
+ need |= 2;
+
+ gi.cvar_set("needpass", "" + need);
+ }
+ }
+
+ /*
+ =================
+ CheckDMRules
+ =================
+ */
+ public static void CheckDMRules() {
+ int i;
+ gclient_t cl;
+
+ if (level.intermissiontime != 0)
+ return;
+
+ if (0 == deathmatch.value)
+ return;
+
+ if (timelimit.value != 0) {
+ if (level.time >= timelimit.value * 60) {
+ gi.bprintf(PRINT_HIGH, "Timelimit hit.\n");
+ EndDMLevel();
+ return;
+ }
+ }
+
+ if (fraglimit.value != 0) {
+ for (i = 0; i < maxclients.value; i++) {
+ cl = game.clients[i];
+ if (!g_edicts[i + 1].inuse)
+ continue;
+
+ if (cl.resp.score >= fraglimit.value) {
+ gi.bprintf(PRINT_HIGH, "Fraglimit hit.\n");
+ EndDMLevel();
+ return;
+ }
+ }
+ }
+ }
+
+ /*
+ =============
+ ExitLevel
+ =============
+ */
+ public static void ExitLevel() {
+ int i;
+ edict_t ent;
+ //char command[256];
+ String command;
+
+ command = "gamemap \"" + level.changemap + "\"\n";
+ gi.AddCommandString(command);
+ level.changemap = null;
+ level.exitintermission = false;
+ level.intermissiontime = 0;
+ ClientEndServerFrames();
+
+ // clear some things before going to next level
+ for (i = 0; i < maxclients.value; i++) {
+ ent = g_edicts[1 + i];
+ if (!ent.inuse)
+ continue;
+ if (ent.health > ent.client.pers.max_health)
+ ent.health = ent.client.pers.max_health;
+ }
+
+ }
+
+ /*
+ ================
+ G_RunFrame
+
+ Advances the world by 0.1 seconds
+ ================
+ */
+ public static void G_RunFrame() {
+ int i;
+ edict_t ent;
+
+ level.framenum++;
+ level.time = level.framenum * FRAMETIME;
+
+ // choose a client for monsters to target this frame
+ Game.AI_SetSightClient();
+
+ // exit intermissions
+
+ if (level.exitintermission) {
+ ExitLevel();
+ return;
+ }
+
+ //
+ // treat each object in turn
+ // even the world gets a chance to think
+ //
+
+ for (i = 0; i < globals.num_edicts; i++) {
+ ent = g_edicts[i];
+ if (!ent.inuse)
+ continue;
+
+ level.current_entity = ent;
+
+ VectorCopy(ent.s.origin, ent.s.old_origin);
+
+ // if the ground entity moved, make sure we are still on it
+ if ((ent.groundentity != null) && (ent.groundentity.linkcount != ent.groundentity_linkcount)) {
+ ent.groundentity = null;
+ if (0 == (ent.flags & (FL_SWIM | FL_FLY)) && (ent.svflags & SVF_MONSTER) != 0) {
+ M.M_CheckGround(ent);
+ }
+ }
+
+ if (i > 0 && i <= maxclients.value) {
+ Game.ClientBeginServerFrame(ent);
+ continue;
+ }
+
+ //TODO: RST: disabled for debugging
+ //if (ent.classname.startsWith("trigger") )//|| ent.classname.startsWith("monster"))
+ //G_RunEntity(ent);
+
+ if (ent == g_edicts[307])
+ G_RunEntity(ent);
+ else if (ent == g_edicts[1])
+ G_RunEntity(ent);
+
+ else if (true)
+ if (ent.classname.startsWith("monster_soldier")
+ || ent.classname.startsWith("target")
+ || ent.classname.startsWith(
+ "misc_explo") //ent.classname.startsWith("func_door")
+ ) //|| ent.classname.startsWith("monster"))
+ G_RunEntity(ent);
+
+ }
+
+ // see if it is time to end a deathmatch
+ CheckDMRules();
+
+ // see if needpass needs updated
+ CheckNeedPass();
+
+ // build the playerstate_t structures for all players
+ ClientEndServerFrames();
+ }
+
+ /*
+ =================
+ GetGameAPI
+
+ Returns a pointer to the structure with all entry points
+ and global variables
+ =================
+ */
+
+ public static game_export_t GetGameApi(game_import_t imp) {
+ gi = imp;
+
+ gi.pointcontents = new pmove_t.PointContentsAdapter() {
+ public int pointcontents(float[] o) {
+ return SV_WORLD.SV_PointContents(o);
+ }
+ };
+
+ globals.apiversion = GAME_API_VERSION;
+ /*
+ globals.Init = InitGame;
+ globals.Shutdown = ShutdownGame;
+ globals.SpawnEntities = SpawnEntities;
+
+ globals.WriteGame = WriteGame;
+ globals.ReadGame = ReadGame;
+ globals.WriteLevel = WriteLevel;
+ globals.ReadLevel = ReadLevel;
+
+ globals.ClientThink = ClientThink;
+ globals.ClientConnect = ClientConnect;
+ globals.ClientUserinfoChanged = ClientUserinfoChanged;
+ globals.ClientDisconnect = ClientDisconnect;
+ globals.ClientBegin = ClientBegin;
+ globals.ClientCommand = ClientCommand;
+ globals.RunFrame = G_RunFrame;
+ globals.ServerCommand = ServerCommand;
+ */
+
+ return globals;
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/GameFunc.java b/src/jake2/game/GameFunc.java
new file mode 100644
index 0000000..2844ff7
--- /dev/null
+++ b/src/jake2/game/GameFunc.java
@@ -0,0 +1,2027 @@
+/*
+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 18.11.2003 by RST.
+// $Id: GameFunc.java,v 1.1 2004-07-07 19:58:58 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class GameFunc extends PlayerView {
+
+ /*
+ =========================================================
+
+ PLATS
+
+ movement options:
+
+ linear
+ smooth start, hard stop
+ smooth start, smooth stop
+
+ start
+ end
+ acceleration
+ speed
+ deceleration
+ begin sound
+ end sound
+ target fired when reaching end
+ wait at end
+
+ object characteristics that use move segments
+ ---------------------------------------------
+ movetype_push, or movetype_stop
+ action when touched
+ action when blocked
+ action when used
+ disabled?
+ auto trigger spawning
+
+
+ =========================================================
+ */
+
+ public final static int PLAT_LOW_TRIGGER = 1;
+
+ public final static int STATE_TOP = 0;
+ public final static int STATE_BOTTOM = 1;
+ public final static int STATE_UP = 2;
+ public final static int STATE_DOWN = 3;
+
+ public final static int DOOR_START_OPEN = 1;
+ public final static int DOOR_REVERSE = 2;
+ public final static int DOOR_CRUSHER = 4;
+ public final static int DOOR_NOMONSTER = 8;
+ public final static int DOOR_TOGGLE = 32;
+ public final static int DOOR_X_AXIS = 64;
+ public final static int DOOR_Y_AXIS = 128;
+
+ //
+ // Support routines for movement (changes in origin using velocity)
+ //
+
+ static EntThinkAdapter Move_Done = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ Math3D.VectorClear(ent.velocity);
+ ent.moveinfo.endfunc.think(ent);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Move_Final = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ if (ent.moveinfo.remaining_distance == 0) {
+ Move_Done.think(ent);
+ return true;
+ }
+
+ Math3D.VectorScale(ent.moveinfo.dir, ent.moveinfo.remaining_distance / FRAMETIME, ent.velocity);
+
+ ent.think = Move_Done;
+ ent.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Move_Begin = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ float frames;
+
+ if ((ent.moveinfo.speed * FRAMETIME) >= ent.moveinfo.remaining_distance) {
+ Move_Final.think(ent);
+ return true;
+ }
+ Math3D.VectorScale(ent.moveinfo.dir, ent.moveinfo.speed, ent.velocity);
+ frames = (float) Math.floor((ent.moveinfo.remaining_distance / ent.moveinfo.speed) / FRAMETIME);
+ ent.moveinfo.remaining_distance -= frames * ent.moveinfo.speed * FRAMETIME;
+ ent.nextthink = level.time + (frames * FRAMETIME);
+ ent.think = Move_Final;
+ return true;
+ }
+ };
+
+
+ static void Move_Calc(edict_t ent, float[] dest, EntThinkAdapter func) {
+ Math3D.VectorClear(ent.velocity);
+ Math3D.VectorSubtract(dest, ent.s.origin, ent.moveinfo.dir);
+ ent.moveinfo.remaining_distance = Math3D.VectorNormalize(ent.moveinfo.dir);
+ ent.moveinfo.endfunc = func;
+
+ if (ent.moveinfo.speed == ent.moveinfo.accel && ent.moveinfo.speed == ent.moveinfo.decel) {
+ if (level.current_entity == ((ent.flags & FL_TEAMSLAVE) != 0 ? ent.teammaster : ent)) {
+ Move_Begin.think(ent);
+ } else {
+ ent.nextthink = level.time + FRAMETIME;
+ ent.think = Move_Begin;
+ }
+ } else {
+ // accelerative
+ ent.moveinfo.current_speed = 0;
+ ent.think = Think_AccelMove;
+ ent.nextthink = level.time + FRAMETIME;
+ }
+ }
+
+ //
+ // Support routines for angular movement (changes in angle using avelocity)
+ //
+
+ static EntThinkAdapter AngleMove_Done = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ Math3D.VectorClear(ent.avelocity);
+ ent.moveinfo.endfunc.think(ent);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter AngleMove_Final = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] move={0,0,0};
+
+ if (ent.moveinfo.state == STATE_UP)
+ Math3D.VectorSubtract(ent.moveinfo.end_angles, ent.s.angles, move);
+ else
+ Math3D.VectorSubtract(ent.moveinfo.start_angles, ent.s.angles, move);
+
+ if (Math3D.VectorCompare(move, vec3_origin) != 0) {
+ AngleMove_Done.think(ent);
+ return true;
+ }
+
+ Math3D.VectorScale(move, 1.0f / FRAMETIME, ent.avelocity);
+
+ ent.think = AngleMove_Done;
+ ent.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter AngleMove_Begin = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] destdelta={0,0,0};
+ float len;
+ float traveltime;
+ float frames;
+
+ // set destdelta to the vector needed to move
+ if (ent.moveinfo.state == STATE_UP)
+ Math3D.VectorSubtract(ent.moveinfo.end_angles, ent.s.angles, destdelta);
+ else
+ Math3D.VectorSubtract(ent.moveinfo.start_angles, ent.s.angles, destdelta);
+
+ // calculate length of vector
+ len = Math3D.VectorLength(destdelta);
+
+ // divide by speed to get time to reach dest
+ traveltime = len / ent.moveinfo.speed;
+
+ if (traveltime < FRAMETIME) {
+ AngleMove_Final.think(ent);
+ return true;
+ }
+
+ frames = (float) (Math.floor(traveltime / FRAMETIME));
+
+ // scale the destdelta vector by the time spent traveling to get velocity
+ Math3D.VectorScale(destdelta, 1.0f / traveltime, ent.avelocity);
+
+ // set nextthink to trigger a think when dest is reached
+ ent.nextthink = level.time + frames * FRAMETIME;
+ ent.think = AngleMove_Final;
+ return true;
+ }
+ };
+
+ static void AngleMove_Calc(edict_t ent, EntThinkAdapter func) {
+ Math3D.VectorClear(ent.avelocity);
+ ent.moveinfo.endfunc = func;
+ if (level.current_entity == ((ent.flags & FL_TEAMSLAVE) != 0 ? ent.teammaster : ent)) {
+ AngleMove_Begin.think(ent);
+ } else {
+ ent.nextthink = level.time + FRAMETIME;
+ ent.think = AngleMove_Begin;
+ }
+ }
+
+ /*
+ ==============
+ Think_AccelMove
+
+ The team has completed a frame of movement, so
+ change the speed for the next frame
+ ==============
+ */
+ static float AccelerationDistance(float target, float rate) {
+ return target * ((target / rate) + 1) / 2;
+ };
+
+ static void plat_CalcAcceleratedMove(moveinfo_t moveinfo) {
+ float accel_dist;
+ float decel_dist;
+
+ moveinfo.move_speed = moveinfo.speed;
+
+ if (moveinfo.remaining_distance < moveinfo.accel) {
+ moveinfo.current_speed = moveinfo.remaining_distance;
+ return;
+ }
+
+ accel_dist = AccelerationDistance(moveinfo.speed, moveinfo.accel);
+ decel_dist = AccelerationDistance(moveinfo.speed, moveinfo.decel);
+
+ if ((moveinfo.remaining_distance - accel_dist - decel_dist) < 0) {
+ float f;
+
+ f = (moveinfo.accel + moveinfo.decel) / (moveinfo.accel * moveinfo.decel);
+ moveinfo.move_speed = (float) ((-2 + Math.sqrt(4 - 4 * f * (-2 * moveinfo.remaining_distance))) / (2 * f));
+ decel_dist = AccelerationDistance(moveinfo.move_speed, moveinfo.decel);
+ }
+
+ moveinfo.decel_distance = decel_dist;
+ };
+
+ static void plat_Accelerate(moveinfo_t moveinfo) {
+ // are we decelerating?
+ if (moveinfo.remaining_distance <= moveinfo.decel_distance) {
+ if (moveinfo.remaining_distance < moveinfo.decel_distance) {
+ if (moveinfo.next_speed != 0) {
+ moveinfo.current_speed = moveinfo.next_speed;
+ moveinfo.next_speed = 0;
+ return;
+ }
+ if (moveinfo.current_speed > moveinfo.decel)
+ moveinfo.current_speed -= moveinfo.decel;
+ }
+ return;
+ }
+
+ // are we at full speed and need to start decelerating during this move?
+ if (moveinfo.current_speed == moveinfo.move_speed)
+ if ((moveinfo.remaining_distance - moveinfo.current_speed) < moveinfo.decel_distance) {
+ float p1_distance;
+ float p2_distance;
+ float distance;
+
+ p1_distance = moveinfo.remaining_distance - moveinfo.decel_distance;
+ p2_distance = moveinfo.move_speed * (1.0f - (p1_distance / moveinfo.move_speed));
+ distance = p1_distance + p2_distance;
+ moveinfo.current_speed = moveinfo.move_speed;
+ moveinfo.next_speed = moveinfo.move_speed - moveinfo.decel * (p2_distance / distance);
+ return;
+ }
+
+ // are we accelerating?
+ if (moveinfo.current_speed < moveinfo.speed) {
+ float old_speed;
+ float p1_distance;
+ float p1_speed;
+ float p2_distance;
+ float distance;
+
+ old_speed = moveinfo.current_speed;
+
+ // figure simple acceleration up to move_speed
+ moveinfo.current_speed += moveinfo.accel;
+ if (moveinfo.current_speed > moveinfo.speed)
+ moveinfo.current_speed = moveinfo.speed;
+
+ // are we accelerating throughout this entire move?
+ if ((moveinfo.remaining_distance - moveinfo.current_speed) >= moveinfo.decel_distance)
+ return;
+
+ // during this move we will accelrate from current_speed to move_speed
+ // and cross over the decel_distance; figure the average speed for the
+ // entire move
+ p1_distance = moveinfo.remaining_distance - moveinfo.decel_distance;
+ p1_speed = (old_speed + moveinfo.move_speed) / 2.0f;
+ p2_distance = moveinfo.move_speed * (1.0f - (p1_distance / p1_speed));
+ distance = p1_distance + p2_distance;
+ moveinfo.current_speed = (p1_speed * (p1_distance / distance)) + (moveinfo.move_speed * (p2_distance / distance));
+ moveinfo.next_speed = moveinfo.move_speed - moveinfo.decel * (p2_distance / distance);
+ return;
+ }
+
+ // we are at constant velocity (move_speed)
+ return;
+ };
+
+ static EntThinkAdapter Think_AccelMove = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ ent.moveinfo.remaining_distance -= ent.moveinfo.current_speed;
+
+ if (ent.moveinfo.current_speed == 0) // starting or blocked
+ plat_CalcAcceleratedMove(ent.moveinfo);
+
+ plat_Accelerate(ent.moveinfo);
+
+ // will the entire move complete on next frame?
+ if (ent.moveinfo.remaining_distance <= ent.moveinfo.current_speed) {
+ Move_Final.think(ent);
+ return true;
+ }
+
+ Math3D.VectorScale(ent.moveinfo.dir, ent.moveinfo.current_speed * 10, ent.velocity);
+ ent.nextthink = level.time + FRAMETIME;
+ ent.think = Think_AccelMove;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter plat_hit_top = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ if (0 == (ent.flags & FL_TEAMSLAVE)) {
+ if (ent.moveinfo.sound_end != 0)
+ gi.sound(ent, CHAN_NO_PHS_ADD + CHAN_VOICE, ent.moveinfo.sound_end, 1, ATTN_STATIC, 0);
+ ent.s.sound = 0;
+ }
+ ent.moveinfo.state = STATE_TOP;
+
+ ent.think = plat_go_down;
+ ent.nextthink = level.time + 3;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter plat_hit_bottom = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ if (0 == (ent.flags & FL_TEAMSLAVE)) {
+ if (ent.moveinfo.sound_end != 0)
+ gi.sound(ent, CHAN_NO_PHS_ADD + CHAN_VOICE, ent.moveinfo.sound_end, 1, ATTN_STATIC, 0);
+ ent.s.sound = 0;
+ }
+ ent.moveinfo.state = STATE_BOTTOM;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter plat_go_down = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ if (0 == (ent.flags & FL_TEAMSLAVE)) {
+ if (ent.moveinfo.sound_start != 0)
+ gi.sound(ent, CHAN_NO_PHS_ADD + CHAN_VOICE, ent.moveinfo.sound_start, 1, ATTN_STATIC, 0);
+ ent.s.sound = ent.moveinfo.sound_middle;
+ }
+ ent.moveinfo.state = STATE_DOWN;
+ Move_Calc(ent, ent.moveinfo.end_origin, plat_hit_bottom);
+ return true;
+ }
+ };
+
+ static void plat_go_up(edict_t ent) {
+ if (0 == (ent.flags & FL_TEAMSLAVE)) {
+ if (ent.moveinfo.sound_start != 0)
+ gi.sound(ent, CHAN_NO_PHS_ADD + CHAN_VOICE, ent.moveinfo.sound_start, 1, ATTN_STATIC, 0);
+ ent.s.sound = ent.moveinfo.sound_middle;
+ }
+ ent.moveinfo.state = STATE_UP;
+ Move_Calc(ent, ent.moveinfo.start_origin, plat_hit_top);
+ }
+
+ static EntBlockedAdapter plat_blocked = new EntBlockedAdapter() {
+ public void blocked(edict_t self, edict_t other) {
+ if (0 == (other.svflags & SVF_MONSTER) && (null == other.client)) {
+ // give it a chance to go away on it's own terms (like gibs)
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+ // if it's still there, nuke it
+ if (other != null)
+ BecomeExplosion1(other);
+ return;
+ }
+
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, self.dmg, 1, 0, MOD_CRUSH);
+
+ if (self.moveinfo.state == STATE_UP)
+ plat_go_down.think(self);
+ else if (self.moveinfo.state == STATE_DOWN)
+ plat_go_up(self);
+
+ }
+ };
+
+ static EntUseAdapter Use_Plat = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ if (ent.think != null)
+ return; // already down
+ plat_go_down.think(ent);
+ }
+ };
+
+ static EntTouchAdapter Touch_Plat_Center = new EntTouchAdapter() {
+ public void touch(edict_t ent, edict_t other, cplane_t plane, csurface_t surf) {
+ if (other.client == null)
+ return;
+
+ if (other.health <= 0)
+ return;
+
+ ent = ent.enemy; // now point at the plat, not the trigger
+ if (ent.moveinfo.state == STATE_BOTTOM)
+ plat_go_up(ent);
+ else if (ent.moveinfo.state == STATE_TOP)
+ ent.nextthink = level.time + 1; // the player is still on the plat, so delay going down
+ }
+ };
+
+ static void plat_spawn_inside_trigger(edict_t ent) {
+ edict_t trigger;
+ float[] tmin={0,0,0}, tmax={0,0,0};
+
+ //
+ // middle trigger
+ //
+ trigger = G_Spawn();
+ trigger.touch = Touch_Plat_Center;
+ trigger.movetype = MOVETYPE_NONE;
+ trigger.solid = SOLID_TRIGGER;
+ trigger.enemy = ent;
+
+ tmin[0] = ent.mins[0] + 25;
+ tmin[1] = ent.mins[1] + 25;
+ tmin[2] = ent.mins[2];
+
+ tmax[0] = ent.maxs[0] - 25;
+ tmax[1] = ent.maxs[1] - 25;
+ tmax[2] = ent.maxs[2] + 8;
+
+ tmin[2] = tmax[2] - (ent.pos1[2] - ent.pos2[2] + st.lip);
+
+ if ((ent.spawnflags & PLAT_LOW_TRIGGER) != 0)
+ tmax[2] = tmin[2] + 8;
+
+ if (tmax[0] - tmin[0] <= 0) {
+ tmin[0] = (ent.mins[0] + ent.maxs[0]) * 0.5f;
+ tmax[0] = tmin[0] + 1;
+ }
+ if (tmax[1] - tmin[1] <= 0) {
+ tmin[1] = (ent.mins[1] + ent.maxs[1]) * 0.5f;
+ tmax[1] = tmin[1] + 1;
+ }
+
+ Math3D.VectorCopy(tmin, trigger.mins);
+ Math3D.VectorCopy(tmax, trigger.maxs);
+
+ gi.linkentity(trigger);
+ }
+
+ /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER
+ speed default 150
+
+ Plats are always drawn in the extended position, so they will light correctly.
+
+ If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
+
+ "speed" overrides default 200.
+ "accel" overrides default 500
+ "lip" overrides default 8 pixel lip
+
+ If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height.
+
+ Set "sounds" to one of the following:
+ 1) base fast
+ 2) chain slow
+ */
+ static void SP_func_plat(edict_t ent) {
+ Math3D.VectorClear(ent.s.angles);
+ ent.solid = SOLID_BSP;
+ ent.movetype = MOVETYPE_PUSH;
+
+ gi.setmodel(ent, ent.model);
+
+ ent.blocked = plat_blocked;
+
+ if (0 == ent.speed)
+ ent.speed = 20;
+ else
+ ent.speed *= 0.1;
+
+ if (ent.accel == 0)
+ ent.accel = 5;
+ else
+ ent.accel *= 0.1;
+
+ if (ent.decel == 0)
+ ent.decel = 5;
+ else
+ ent.decel *= 0.1;
+
+ if (ent.dmg == 0)
+ ent.dmg = 2;
+
+ if (st.lip == 0)
+ st.lip = 8;
+
+ // pos1 is the top position, pos2 is the bottom
+ Math3D.VectorCopy(ent.s.origin, ent.pos1);
+ Math3D.VectorCopy(ent.s.origin, ent.pos2);
+ if (st.height != 0)
+ ent.pos2[2] -= st.height;
+ else
+ ent.pos2[2] -= (ent.maxs[2] - ent.mins[2]) - st.lip;
+
+ ent.use = Use_Plat;
+
+ plat_spawn_inside_trigger(ent); // the "start moving" trigger
+
+ if (ent.targetname == null) {
+ ent.moveinfo.state = STATE_UP;
+ } else {
+ Math3D.VectorCopy(ent.pos2, ent.s.origin);
+ gi.linkentity(ent);
+ ent.moveinfo.state = STATE_BOTTOM;
+ }
+
+ ent.moveinfo.speed = ent.speed;
+ ent.moveinfo.accel = ent.accel;
+ ent.moveinfo.decel = ent.decel;
+ ent.moveinfo.wait = ent.wait;
+ Math3D.VectorCopy(ent.pos1, ent.moveinfo.start_origin);
+ Math3D.VectorCopy(ent.s.angles, ent.moveinfo.start_angles);
+ Math3D.VectorCopy(ent.pos2, ent.moveinfo.end_origin);
+ Math3D.VectorCopy(ent.s.angles, ent.moveinfo.end_angles);
+
+ ent.moveinfo.sound_start = gi.soundindex("plats/pt1_strt.wav");
+ ent.moveinfo.sound_middle = gi.soundindex("plats/pt1_mid.wav");
+ ent.moveinfo.sound_end = gi.soundindex("plats/pt1_end.wav");
+ }
+
+ // ====================================================================
+
+ /*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS TOUCH_PAIN STOP ANIMATED ANIMATED_FAST
+ You need to have an origin brush as part of this entity. The center of that brush will be
+ the point around which it is rotated. It will rotate around the Z axis by default. You can
+ check either the X_AXIS or Y_AXIS box to change that.
+
+ "speed" determines how fast it moves; default value is 100.
+ "dmg" damage to inflict when blocked (2 default)
+
+ REVERSE will cause the it to rotate in the opposite direction.
+ STOP mean it will stop moving instead of pushing entities
+ */
+
+ static EntBlockedAdapter rotating_blocked = new EntBlockedAdapter() {
+ public void blocked(edict_t self, edict_t other) {
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, self.dmg, 1, 0, MOD_CRUSH);
+ }
+ };
+
+ static EntTouchAdapter rotating_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (self.avelocity[0] != 0 || self.avelocity[1] != 0 || self.avelocity[2] != 0)
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, self.dmg, 1, 0, MOD_CRUSH);
+ }
+ };
+
+ static EntUseAdapter rotating_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (0 == Math3D.VectorCompare(self.avelocity, vec3_origin)) {
+ self.s.sound = 0;
+ Math3D.VectorClear(self.avelocity);
+ self.touch = null;
+ } else {
+ self.s.sound = self.moveinfo.sound_middle;
+ Math3D.VectorScale(self.movedir, self.speed, self.avelocity);
+ if ((self.spawnflags & 16) != 0)
+ self.touch = rotating_touch;
+ }
+ }
+ };
+ static EntThinkAdapter SP_func_rotating = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ ent.solid = SOLID_BSP;
+ if ((ent.spawnflags & 32) != 0)
+ ent.movetype = MOVETYPE_STOP;
+ else
+ ent.movetype = MOVETYPE_PUSH;
+
+ // set the axis of rotation
+ Math3D.VectorClear(ent.movedir);
+ if ((ent.spawnflags & 4) != 0)
+ ent.movedir[2] = 1.0f;
+ else if ((ent.spawnflags & 8) != 0)
+ ent.movedir[0] = 1.0f;
+ else // Z_AXIS
+ ent.movedir[1] = 1.0f;
+
+ // check for reverse rotation
+ if ((ent.spawnflags & 2) != 0)
+ Math3D.VectorNegate(ent.movedir, ent.movedir);
+
+ if (0 == ent.speed)
+ ent.speed = 100;
+ if (0 == ent.dmg)
+ ent.dmg = 2;
+
+ // ent.moveinfo.sound_middle = "doors/hydro1.wav";
+
+ ent.use = rotating_use;
+ if (ent.dmg != 0)
+ ent.blocked = rotating_blocked;
+
+ if ((ent.spawnflags & 1) != 0)
+ ent.use.use(ent, null, null);
+
+ if ((ent.spawnflags & 64) != 0)
+ ent.s.effects |= EF_ANIM_ALL;
+ if ((ent.spawnflags & 128) != 0)
+ ent.s.effects |= EF_ANIM_ALLFAST;
+
+ gi.setmodel(ent, ent.model);
+ gi.linkentity(ent);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ BUTTONS
+
+ ======================================================================
+ */
+
+ /*QUAKED func_button (0 .5 .8) ?
+ When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+ "angle" determines the opening direction
+ "target" all entities with a matching targetname will be used
+ "speed" override the default 40 speed
+ "wait" override the default 1 second wait (-1 = never return)
+ "lip" override the default 4 pixel lip remaining at end of move
+ "health" if set, the button must be killed instead of touched
+ "sounds"
+ 1) silent
+ 2) steam metal
+ 3) wooden clunk
+ 4) metallic click
+ 5) in-out
+ */
+
+ static EntThinkAdapter button_done = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.moveinfo.state = STATE_BOTTOM;
+ self.s.effects &= ~EF_ANIM23;
+ self.s.effects |= EF_ANIM01;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter button_return = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.moveinfo.state = STATE_DOWN;
+
+ Move_Calc(self, self.moveinfo.start_origin, button_done);
+
+ self.s.frame = 0;
+
+ if (self.health != 0)
+ self.takedamage = DAMAGE_YES;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter button_wait = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.moveinfo.state = STATE_TOP;
+ self.s.effects &= ~EF_ANIM01;
+ self.s.effects |= EF_ANIM23;
+
+ G_UseTargets(self, self.activator);
+ self.s.frame = 1;
+ if (self.moveinfo.wait >= 0) {
+ self.nextthink = level.time + self.moveinfo.wait;
+ self.think = button_return;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter button_fire = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.moveinfo.state == STATE_UP || self.moveinfo.state == STATE_TOP)
+ return true;
+
+ self.moveinfo.state = STATE_UP;
+ if (self.moveinfo.sound_start != 0 && 0 == (self.flags & FL_TEAMSLAVE))
+ gi.sound(self, CHAN_NO_PHS_ADD + CHAN_VOICE, self.moveinfo.sound_start, 1, ATTN_STATIC, 0);
+ Move_Calc(self, self.moveinfo.end_origin, button_wait);
+ return true;
+ }
+ };
+
+ static EntUseAdapter button_use = new EntUseAdapter() {
+ public boolean think(edict_t self, edict_t activator) {
+ self.activator = activator;
+ button_fire.think(self);
+ return true;
+ }
+ };
+
+ static EntTouchAdapter button_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (null == other.client)
+ return;
+
+ if (other.health <= 0)
+ return;
+
+ self.activator = other;
+ button_fire.think(self);
+
+ }
+ };
+
+ static EntDieAdapter button_killed = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ self.activator = attacker;
+ self.health = self.max_health;
+ self.takedamage = DAMAGE_NO;
+ button_fire.think(self);
+
+ }
+ };
+
+ static EntThinkAdapter SP_func_button = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] abs_movedir={0,0,0};
+ float dist;
+
+ G_SetMovedir(ent.s.angles, ent.movedir);
+ ent.movetype = MOVETYPE_STOP;
+ ent.solid = SOLID_BSP;
+ gi.setmodel(ent, ent.model);
+
+ if (ent.sounds != 1)
+ ent.moveinfo.sound_start = gi.soundindex("switches/butn2.wav");
+
+ if (0 == ent.speed)
+ ent.speed = 40;
+ if (0 == ent.accel)
+ ent.accel = ent.speed;
+ if (0 == ent.decel)
+ ent.decel = ent.speed;
+
+ if (0 == ent.wait)
+ ent.wait = 3;
+ if (0 == st.lip)
+ st.lip = 4;
+
+ Math3D.VectorCopy(ent.s.origin, ent.pos1);
+ abs_movedir[0] = (float) Math.abs(ent.movedir[0]);
+ abs_movedir[1] = (float) Math.abs(ent.movedir[1]);
+ abs_movedir[2] = (float) Math.abs(ent.movedir[2]);
+ dist = abs_movedir[0] * ent.size[0] + abs_movedir[1] * ent.size[1] + abs_movedir[2] * ent.size[2] - st.lip;
+ Math3D.VectorMA(ent.pos1, dist, ent.movedir, ent.pos2);
+
+ ent.use = button_use;
+ ent.s.effects |= EF_ANIM01;
+
+ if (ent.health != 0) {
+ ent.max_health = ent.health;
+ ent.die = button_killed;
+ ent.takedamage = DAMAGE_YES;
+ } else if (null == ent.targetname)
+ ent.touch = button_touch;
+
+ ent.moveinfo.state = STATE_BOTTOM;
+
+ ent.moveinfo.speed = ent.speed;
+ ent.moveinfo.accel = ent.accel;
+ ent.moveinfo.decel = ent.decel;
+ ent.moveinfo.wait = ent.wait;
+ Math3D.VectorCopy(ent.pos1, ent.moveinfo.start_origin);
+ Math3D.VectorCopy(ent.s.angles, ent.moveinfo.start_angles);
+ Math3D.VectorCopy(ent.pos2, ent.moveinfo.end_origin);
+ Math3D.VectorCopy(ent.s.angles, ent.moveinfo.end_angles);
+
+ gi.linkentity(ent);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ DOORS
+
+ spawn a trigger surrounding the entire team unless it is
+ already targeted by another
+
+ ======================================================================
+ */
+
+ /*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER NOMONSTER ANIMATED TOGGLE ANIMATED_FAST
+ TOGGLE wait in both the start and end states for a trigger event.
+ START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+ NOMONSTER monsters will not trigger this door
+
+ "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+ "angle" determines the opening direction
+ "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+ "health" if set, door must be shot open
+ "speed" movement speed (100 default)
+ "wait" wait before returning (3 default, -1 = never return)
+ "lip" lip remaining at end of move (8 default)
+ "dmg" damage to inflict when blocked (2 default)
+ "sounds"
+ 1) silent
+ 2) light
+ 3) medium
+ 4) heavy
+ */
+
+ static void door_use_areaportals(edict_t self, boolean open) {
+ edict_t t = null;
+
+ if (self.target == null)
+ return;
+
+ EdictIterator edit = null;
+
+ while ((edit = G_Find(edit, findByTarget, self.target)) != null) {
+ t = edit.o;
+ if (Lib.Q_stricmp(t.classname, "func_areaportal") == 0) {
+ gi.SetAreaPortalState(t.style, open);
+ }
+ }
+ }
+
+ static EntThinkAdapter door_hit_top = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (0 == (self.flags & FL_TEAMSLAVE)) {
+ if (self.moveinfo.sound_end != 0)
+ gi.sound(self, CHAN_NO_PHS_ADD + CHAN_VOICE, self.moveinfo.sound_end, 1, ATTN_STATIC, 0);
+ self.s.sound = 0;
+ }
+ self.moveinfo.state = STATE_TOP;
+ if ((self.spawnflags & DOOR_TOGGLE) != 0)
+ return true;
+ if (self.moveinfo.wait >= 0) {
+ self.think = door_go_down;
+ self.nextthink = level.time + self.moveinfo.wait;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_hit_bottom = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (0 == (self.flags & FL_TEAMSLAVE)) {
+ if (self.moveinfo.sound_end != 0)
+ gi.sound(self, CHAN_NO_PHS_ADD + CHAN_VOICE, self.moveinfo.sound_end, 1, ATTN_STATIC, 0);
+ self.s.sound = 0;
+ }
+ self.moveinfo.state = STATE_BOTTOM;
+ door_use_areaportals(self, false);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_go_down = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (0 == (self.flags & FL_TEAMSLAVE)) {
+ if (self.moveinfo.sound_start != 0)
+ gi.sound(self, CHAN_NO_PHS_ADD + CHAN_VOICE, self.moveinfo.sound_start, 1, ATTN_STATIC, 0);
+ self.s.sound = self.moveinfo.sound_middle;
+ }
+ if (self.max_health != 0) {
+ self.takedamage = DAMAGE_YES;
+ self.health = self.max_health;
+ }
+
+ self.moveinfo.state = STATE_DOWN;
+ if (Lib.strcmp(self.classname, "func_door") == 0)
+ Move_Calc(self, self.moveinfo.start_origin, door_hit_bottom);
+ else if (Lib.strcmp(self.classname, "func_door_rotating") == 0)
+ AngleMove_Calc(self, door_hit_bottom);
+ return true;
+ }
+ };
+
+ static void door_go_up(edict_t self, edict_t activator) {
+ if (self.moveinfo.state == STATE_UP)
+ return; // already going up
+
+ if (self.moveinfo.state == STATE_TOP) { // reset top wait time
+ if (self.moveinfo.wait >= 0)
+ self.nextthink = level.time + self.moveinfo.wait;
+ return;
+ }
+
+ if (0 == (self.flags & FL_TEAMSLAVE)) {
+ if (self.moveinfo.sound_start != 0)
+ gi.sound(self, CHAN_NO_PHS_ADD + CHAN_VOICE, self.moveinfo.sound_start, 1, ATTN_STATIC, 0);
+ self.s.sound = self.moveinfo.sound_middle;
+ }
+ self.moveinfo.state = STATE_UP;
+ if (Lib.strcmp(self.classname, "func_door") == 0)
+ Move_Calc(self, self.moveinfo.end_origin, door_hit_top);
+ else if (Lib.strcmp(self.classname, "func_door_rotating") == 0)
+ AngleMove_Calc(self, door_hit_top);
+
+ G_UseTargets(self, activator);
+ door_use_areaportals(self, true);
+ }
+
+ static EntUseAdapter door_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ edict_t ent;
+
+ if ((self.flags & FL_TEAMSLAVE) != 0)
+ return;
+
+ if ((self.spawnflags & DOOR_TOGGLE) != 0) {
+ if (self.moveinfo.state == STATE_UP || self.moveinfo.state == STATE_TOP) {
+ // trigger all paired doors
+ for (ent = self; ent != null; ent = ent.teamchain) {
+ ent.message = null;
+ ent.touch = null;
+ door_go_down.think(ent);
+ }
+ return;
+ }
+ }
+
+ // trigger all paired doors
+ for (ent = self; ent != null; ent = ent.teamchain) {
+ ent.message = null;
+ ent.touch = null;
+ door_go_up(ent, activator);
+ }
+ }
+ };
+
+ static EntTouchAdapter Touch_DoorTrigger = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (other.health <= 0)
+ return;
+
+ if (0 == (other.svflags & SVF_MONSTER) && (null == other.client))
+ return;
+
+ if (0 != (self.owner.spawnflags & DOOR_NOMONSTER) && 0 != (other.svflags & SVF_MONSTER))
+ return;
+
+ if (level.time < self.touch_debounce_time)
+ return;
+ self.touch_debounce_time = level.time + 1.0f;
+
+ door_use.use(self.owner, other, other);
+ }
+ };
+
+ static EntThinkAdapter Think_CalcMoveSpeed = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent;
+ float min;
+ float time;
+ float newspeed;
+ float ratio;
+ float dist;
+
+ if ((self.flags & FL_TEAMSLAVE) != 0)
+ return true; // only the team master does this
+
+ // find the smallest distance any member of the team will be moving
+ min = Math.abs(self.moveinfo.distance);
+ for (ent = self.teamchain; ent != null; ent = ent.teamchain) {
+ dist = Math.abs(ent.moveinfo.distance);
+ if (dist < min)
+ min = dist;
+ }
+
+ time = min / self.moveinfo.speed;
+
+ // adjust speeds so they will all complete at the same time
+ for (ent = self; ent != null; ent = ent.teamchain) {
+ newspeed = Math.abs(ent.moveinfo.distance) / time;
+ ratio = newspeed / ent.moveinfo.speed;
+ if (ent.moveinfo.accel == ent.moveinfo.speed)
+ ent.moveinfo.accel = newspeed;
+ else
+ ent.moveinfo.accel *= ratio;
+ if (ent.moveinfo.decel == ent.moveinfo.speed)
+ ent.moveinfo.decel = newspeed;
+ else
+ ent.moveinfo.decel *= ratio;
+ ent.moveinfo.speed = newspeed;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Think_SpawnDoorTrigger = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ edict_t other;
+ float[] mins={0,0,0}, maxs={0,0,0};
+
+ if ((ent.flags & FL_TEAMSLAVE) != 0)
+ return true; // only the team leader spawns a trigger
+
+ Math3D.VectorCopy(ent.absmin, mins);
+ Math3D.VectorCopy(ent.absmax, maxs);
+
+ for (other = ent.teamchain; other != null; other = other.teamchain) {
+ AddPointToBounds(other.absmin, mins, maxs);
+ AddPointToBounds(other.absmax, mins, maxs);
+ }
+
+ // expand
+ mins[0] -= 60;
+ mins[1] -= 60;
+ maxs[0] += 60;
+ maxs[1] += 60;
+
+ other = G_Spawn();
+ Math3D.VectorCopy(mins, other.mins);
+ Math3D.VectorCopy(maxs, other.maxs);
+ other.owner = ent;
+ other.solid = SOLID_TRIGGER;
+ other.movetype = MOVETYPE_NONE;
+ other.touch = Touch_DoorTrigger;
+ gi.linkentity(other);
+
+ if ((ent.spawnflags & DOOR_START_OPEN) != 0)
+ door_use_areaportals(ent, true);
+
+ Think_CalcMoveSpeed.think(ent);
+ return true;
+ }
+ };
+
+ static EntBlockedAdapter door_blocked = new EntBlockedAdapter() {
+ public void blocked(edict_t self, edict_t other) {
+ edict_t ent;
+
+ if (0 == (other.svflags & SVF_MONSTER) && (null == other.client)) {
+ // give it a chance to go away on it's own terms (like gibs)
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+ // if it's still there, nuke it
+ if (other != null)
+ BecomeExplosion1(other);
+ return;
+ }
+
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, self.dmg, 1, 0, MOD_CRUSH);
+
+ if ((self.spawnflags & DOOR_CRUSHER) != 0)
+ return;
+
+ // if a door has a negative wait, it would never come back if blocked,
+ // so let it just squash the object to death real fast
+ if (self.moveinfo.wait >= 0) {
+ if (self.moveinfo.state == STATE_DOWN) {
+ for (ent = self.teammaster; ent != null; ent = ent.teamchain)
+ door_go_up(ent, ent.activator);
+ } else {
+ for (ent = self.teammaster; ent != null; ent = ent.teamchain)
+ door_go_down.think(ent);
+ }
+ }
+ }
+ };
+
+ static EntDieAdapter door_killed = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ edict_t ent;
+
+ for (ent = self.teammaster; ent != null; ent = ent.teamchain) {
+ ent.health = ent.max_health;
+ ent.takedamage = DAMAGE_NO;
+ }
+ door_use.use(self.teammaster, attacker, attacker);
+ }
+ };
+
+ static EntTouchAdapter door_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (null == other.client)
+ return;
+
+ if (level.time < self.touch_debounce_time)
+ return;
+ self.touch_debounce_time = level.time + 5.0f;
+
+ gi.centerprintf(other, self.message);
+ gi.sound(other, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+
+ static EntThinkAdapter SP_func_door = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] abs_movedir={0,0,0};
+
+ if (ent.sounds != 1) {
+ ent.moveinfo.sound_start = gi.soundindex("doors/dr1_strt.wav");
+ ent.moveinfo.sound_middle = gi.soundindex("doors/dr1_mid.wav");
+ ent.moveinfo.sound_end = gi.soundindex("doors/dr1_end.wav");
+ }
+
+ G_SetMovedir(ent.s.angles, ent.movedir);
+ ent.movetype = MOVETYPE_PUSH;
+ ent.solid = SOLID_BSP;
+ gi.setmodel(ent, ent.model);
+
+ ent.blocked = door_blocked;
+ ent.use = door_use;
+
+ if (0 == ent.speed)
+ ent.speed = 100;
+ if (deathmatch.value != 0)
+ ent.speed *= 2;
+
+ if (0 == ent.accel)
+ ent.accel = ent.speed;
+ if (0 == ent.decel)
+ ent.decel = ent.speed;
+
+ if (0 == ent.wait)
+ ent.wait = 3;
+ if (0 == st.lip)
+ st.lip = 8;
+ if (0 == ent.dmg)
+ ent.dmg = 2;
+
+ // calculate second position
+ Math3D.VectorCopy(ent.s.origin, ent.pos1);
+ abs_movedir[0] = Math.abs(ent.movedir[0]);
+ abs_movedir[1] = Math.abs(ent.movedir[1]);
+ abs_movedir[2] = Math.abs(ent.movedir[2]);
+ ent.moveinfo.distance =
+ abs_movedir[0] * ent.size[0] + abs_movedir[1] * ent.size[1] + abs_movedir[2] * ent.size[2] - st.lip;
+ Math3D.VectorMA(ent.pos1, ent.moveinfo.distance, ent.movedir, ent.pos2);
+
+ // if it starts open, switch the positions
+ if ((ent.spawnflags & DOOR_START_OPEN) != 0) {
+ Math3D.VectorCopy(ent.pos2, ent.s.origin);
+ Math3D.VectorCopy(ent.pos1, ent.pos2);
+ Math3D.VectorCopy(ent.s.origin, ent.pos1);
+ }
+
+ ent.moveinfo.state = STATE_BOTTOM;
+
+ if (ent.health != 0) {
+ ent.takedamage = DAMAGE_YES;
+ ent.die = door_killed;
+ ent.max_health = ent.health;
+ } else if (ent.targetname != null && ent.message != null) {
+ gi.soundindex("misc/talk.wav");
+ ent.touch = door_touch;
+ }
+
+ ent.moveinfo.speed = ent.speed;
+ ent.moveinfo.accel = ent.accel;
+ ent.moveinfo.decel = ent.decel;
+ ent.moveinfo.wait = ent.wait;
+ Math3D.VectorCopy(ent.pos1, ent.moveinfo.start_origin);
+ Math3D.VectorCopy(ent.s.angles, ent.moveinfo.start_angles);
+ Math3D.VectorCopy(ent.pos2, ent.moveinfo.end_origin);
+ Math3D.VectorCopy(ent.s.angles, ent.moveinfo.end_angles);
+
+ if ((ent.spawnflags & 16) != 0)
+ ent.s.effects |= EF_ANIM_ALL;
+ if ((ent.spawnflags & 64) != 0)
+ ent.s.effects |= EF_ANIM_ALLFAST;
+
+ // to simplify logic elsewhere, make non-teamed doors into a team of one
+ if (null == ent.team)
+ ent.teammaster = ent;
+
+ gi.linkentity(ent);
+
+ ent.nextthink = level.time + FRAMETIME;
+ if (ent.health != 0 || ent.targetname != null)
+ ent.think = Think_CalcMoveSpeed;
+ else
+ ent.think = Think_SpawnDoorTrigger;
+ return true;
+ }
+ };
+
+ /*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE CRUSHER NOMONSTER ANIMATED TOGGLE X_AXIS Y_AXIS
+ TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+ START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+ NOMONSTER monsters will not trigger this door
+
+ You need to have an origin brush as part of this entity. The center of that brush will be
+ the point around which it is rotated. It will rotate around the Z axis by default. You can
+ check either the X_AXIS or Y_AXIS box to change that.
+
+ "distance" is how many degrees the door will be rotated.
+ "speed" determines how fast the door moves; default value is 100.
+
+ REVERSE will cause the door to rotate in the opposite direction.
+
+ "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+ "angle" determines the opening direction
+ "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+ "health" if set, door must be shot open
+ "speed" movement speed (100 default)
+ "wait" wait before returning (3 default, -1 = never return)
+ "dmg" damage to inflict when blocked (2 default)
+ "sounds"
+ 1) silent
+ 2) light
+ 3) medium
+ 4) heavy
+ */
+
+ static EntThinkAdapter SP_func_door_rotating = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ Math3D.VectorClear(ent.s.angles);
+
+ // set the axis of rotation
+ Math3D.VectorClear(ent.movedir);
+ if ((ent.spawnflags & DOOR_X_AXIS) != 0)
+ ent.movedir[2] = 1.0f;
+ else if ((ent.spawnflags & DOOR_Y_AXIS) != 0)
+ ent.movedir[0] = 1.0f;
+ else // Z_AXIS
+ ent.movedir[1] = 1.0f;
+
+ // check for reverse rotation
+ if ((ent.spawnflags & DOOR_REVERSE) != 0)
+ Math3D.VectorNegate(ent.movedir, ent.movedir);
+
+ if (0 == st.distance) {
+ gi.dprintf(ent.classname + " at " + Lib.vtos(ent.s.origin) + " with no distance set\n");
+ st.distance = 90;
+ }
+
+ Math3D.VectorCopy(ent.s.angles, ent.pos1);
+ Math3D.VectorMA(ent.s.angles, st.distance, ent.movedir, ent.pos2);
+ ent.moveinfo.distance = st.distance;
+
+ ent.movetype = MOVETYPE_PUSH;
+ ent.solid = SOLID_BSP;
+ gi.setmodel(ent, ent.model);
+
+ ent.blocked = door_blocked;
+ ent.use = door_use;
+
+ if (0 == ent.speed)
+ ent.speed = 100;
+ if (0 == ent.accel)
+ ent.accel = ent.speed;
+ if (0 == ent.decel)
+ ent.decel = ent.speed;
+
+ if (0 == ent.wait)
+ ent.wait = 3;
+ if (0 == ent.dmg)
+ ent.dmg = 2;
+
+ if (ent.sounds != 1) {
+ ent.moveinfo.sound_start = gi.soundindex("doors/dr1_strt.wav");
+ ent.moveinfo.sound_middle = gi.soundindex("doors/dr1_mid.wav");
+ ent.moveinfo.sound_end = gi.soundindex("doors/dr1_end.wav");
+ }
+
+ // if it starts open, switch the positions
+ if ((ent.spawnflags & DOOR_START_OPEN) != 0) {
+ Math3D.VectorCopy(ent.pos2, ent.s.angles);
+ Math3D.VectorCopy(ent.pos1, ent.pos2);
+ Math3D.VectorCopy(ent.s.angles, ent.pos1);
+ Math3D.VectorNegate(ent.movedir, ent.movedir);
+ }
+
+ if (ent.health != 0) {
+ ent.takedamage = DAMAGE_YES;
+ ent.die = door_killed;
+ ent.max_health = ent.health;
+ }
+
+ if (ent.targetname != null && ent.message != null) {
+ gi.soundindex("misc/talk.wav");
+ ent.touch = door_touch;
+ }
+
+ ent.moveinfo.state = STATE_BOTTOM;
+ ent.moveinfo.speed = ent.speed;
+ ent.moveinfo.accel = ent.accel;
+ ent.moveinfo.decel = ent.decel;
+ ent.moveinfo.wait = ent.wait;
+ Math3D.VectorCopy(ent.s.origin, ent.moveinfo.start_origin);
+ Math3D.VectorCopy(ent.pos1, ent.moveinfo.start_angles);
+ Math3D.VectorCopy(ent.s.origin, ent.moveinfo.end_origin);
+ Math3D.VectorCopy(ent.pos2, ent.moveinfo.end_angles);
+
+ if ((ent.spawnflags & 16) != 0)
+ ent.s.effects |= EF_ANIM_ALL;
+
+ // to simplify logic elsewhere, make non-teamed doors into a team of one
+ if (ent.team == null)
+ ent.teammaster = ent;
+
+ gi.linkentity(ent);
+
+ ent.nextthink = level.time + FRAMETIME;
+ if (ent.health != 0 || ent.targetname != null)
+ ent.think = Think_CalcMoveSpeed;
+ else
+ ent.think = Think_SpawnDoorTrigger;
+ return true;
+ }
+ };
+
+ /*QUAKED func_water (0 .5 .8) ? START_OPEN
+ func_water is a moveable water brush. It must be targeted to operate. Use a non-water texture at your own risk.
+
+ START_OPEN causes the water to move to its destination when spawned and operate in reverse.
+
+ "angle" determines the opening direction (up or down only)
+ "speed" movement speed (25 default)
+ "wait" wait before returning (-1 default, -1 = TOGGLE)
+ "lip" lip remaining at end of move (0 default)
+ "sounds" (yes, these need to be changed)
+ 0) no sound
+ 1) water
+ 2) lava
+ */
+
+ static void SP_func_water(edict_t self) {
+ float[] abs_movedir={0,0,0};
+
+ G_SetMovedir(self.s.angles, self.movedir);
+ self.movetype = MOVETYPE_PUSH;
+ self.solid = SOLID_BSP;
+ gi.setmodel(self, self.model);
+
+ switch (self.sounds) {
+ default :
+ break;
+
+ case 1 : // water
+ self.moveinfo.sound_start = gi.soundindex("world/mov_watr.wav");
+ self.moveinfo.sound_end = gi.soundindex("world/stp_watr.wav");
+ break;
+
+ case 2 : // lava
+ self.moveinfo.sound_start = gi.soundindex("world/mov_watr.wav");
+ self.moveinfo.sound_end = gi.soundindex("world/stp_watr.wav");
+ break;
+ }
+
+ // calculate second position
+ Math3D.VectorCopy(self.s.origin, self.pos1);
+ abs_movedir[0] = Math.abs(self.movedir[0]);
+ abs_movedir[1] = Math.abs(self.movedir[1]);
+ abs_movedir[2] = Math.abs(self.movedir[2]);
+ self.moveinfo.distance =
+ abs_movedir[0] * self.size[0] + abs_movedir[1] * self.size[1] + abs_movedir[2] * self.size[2] - st.lip;
+ Math3D.VectorMA(self.pos1, self.moveinfo.distance, self.movedir, self.pos2);
+
+ // if it starts open, switch the positions
+ if ((self.spawnflags & DOOR_START_OPEN) != 0) {
+ Math3D.VectorCopy(self.pos2, self.s.origin);
+ Math3D.VectorCopy(self.pos1, self.pos2);
+ Math3D.VectorCopy(self.s.origin, self.pos1);
+ }
+
+ Math3D.VectorCopy(self.pos1, self.moveinfo.start_origin);
+ Math3D.VectorCopy(self.s.angles, self.moveinfo.start_angles);
+ Math3D.VectorCopy(self.pos2, self.moveinfo.end_origin);
+ Math3D.VectorCopy(self.s.angles, self.moveinfo.end_angles);
+
+ self.moveinfo.state = STATE_BOTTOM;
+
+ if (0 == self.speed)
+ self.speed = 25;
+ self.moveinfo.accel = self.moveinfo.decel = self.moveinfo.speed = self.speed;
+
+ if (0 == self.wait)
+ self.wait = -1;
+ self.moveinfo.wait = self.wait;
+
+ self.use = door_use;
+
+ if (self.wait == -1)
+ self.spawnflags |= DOOR_TOGGLE;
+
+ self.classname = "func_door";
+
+ gi.linkentity(self);
+ }
+
+ public final static int TRAIN_START_ON = 1;
+ public final static int TRAIN_TOGGLE = 2;
+ public final static int TRAIN_BLOCK_STOPS = 4;
+
+ /*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
+ Trains are moving platforms that players can ride.
+ The targets origin specifies the min point of the train at each corner.
+ The train spawns at the first target it is pointing at.
+ If the train is the target of a button or trigger, it will not begin moving until activated.
+ speed default 100
+ dmg default 2
+ noise looping sound to play when the train is in motion
+
+ */
+
+ static EntBlockedAdapter train_blocked = new EntBlockedAdapter() {
+
+ public void blocked(edict_t self, edict_t other) {
+ if (0 == (other.svflags & SVF_MONSTER) && (null == other.client)) {
+ // give it a chance to go away on it's own terms (like gibs)
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+ // if it's still there, nuke it
+ if (other != null)
+ BecomeExplosion1(other);
+ return;
+ }
+
+ if (level.time < self.touch_debounce_time)
+ return;
+
+ if (self.dmg == 0)
+ return;
+ self.touch_debounce_time = level.time + 0.5f;
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, self.dmg, 1, 0, MOD_CRUSH);
+ }
+ };
+
+ static EntThinkAdapter train_wait = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.target_ent.pathtarget != null) {
+ String savetarget;
+ edict_t ent;
+
+ ent = self.target_ent;
+ savetarget = ent.target;
+ ent.target = ent.pathtarget;
+ G_UseTargets(ent, self.activator);
+ ent.target = savetarget;
+
+ // make sure we didn't get killed by a killtarget
+ if (!self.inuse)
+ return true;
+ }
+
+ if (self.moveinfo.wait != 0) {
+ if (self.moveinfo.wait > 0) {
+ self.nextthink = level.time + self.moveinfo.wait;
+ self.think = train_next;
+ } else if (0 != (self.spawnflags & TRAIN_TOGGLE)) // && wait < 0
+ {
+ train_next.think(self);
+ self.spawnflags &= ~TRAIN_START_ON;
+ Math3D.VectorClear(self.velocity);
+ self.nextthink = 0;
+ }
+
+ if (0 == (self.flags & FL_TEAMSLAVE)) {
+ if (self.moveinfo.sound_end != 0)
+ gi.sound(self, CHAN_NO_PHS_ADD + CHAN_VOICE, self.moveinfo.sound_end, 1, ATTN_STATIC, 0);
+ self.s.sound = 0;
+ }
+ } else {
+ train_next.think(self);
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter train_next = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent=null;
+ float[] dest={0,0,0};
+ boolean first;
+
+ first = true;
+
+ boolean dogoto = true;
+ while (dogoto) {
+ if (null == self.target) {
+ // gi.dprintf ("train_next: no next target\n");
+ return true;
+ }
+
+ ent = G_PickTarget(self.target);
+ if (null == ent) {
+ gi.dprintf("train_next: bad target " + self.target + "\n");
+ return true;
+ }
+
+ self.target = ent.target;
+ dogoto = false;
+ // check for a teleport path_corner
+ if ((ent.spawnflags & 1) != 0) {
+ if (!first) {
+ gi.dprintf("connected teleport path_corners, see " + ent.classname + " at " + Lib.vtos(ent.s.origin) + "\n");
+ return true;
+ }
+ first = false;
+ Math3D.VectorSubtract(ent.s.origin, self.mins, self.s.origin);
+ Math3D.VectorCopy(self.s.origin, self.s.old_origin);
+ self.s.event = EV_OTHER_TELEPORT;
+ gi.linkentity(self);
+ dogoto = true;
+ }
+ }
+ self.moveinfo.wait = ent.wait;
+ self.target_ent = ent;
+
+ if (0 == (self.flags & FL_TEAMSLAVE)) {
+ if (self.moveinfo.sound_start != 0)
+ gi.sound(self, CHAN_NO_PHS_ADD + CHAN_VOICE, self.moveinfo.sound_start, 1, ATTN_STATIC, 0);
+ self.s.sound = self.moveinfo.sound_middle;
+ }
+
+ Math3D.VectorSubtract(ent.s.origin, self.mins, dest);
+ self.moveinfo.state = STATE_TOP;
+ Math3D.VectorCopy(self.s.origin, self.moveinfo.start_origin);
+ Math3D.VectorCopy(dest, self.moveinfo.end_origin);
+ Move_Calc(self, dest, train_wait);
+ self.spawnflags |= TRAIN_START_ON;
+ return true;
+ }
+ };
+
+ static void train_resume(edict_t self) {
+ edict_t ent;
+ float[] dest={0,0,0};
+
+ ent = self.target_ent;
+
+ Math3D.VectorSubtract(ent.s.origin, self.mins, dest);
+ self.moveinfo.state = STATE_TOP;
+ Math3D.VectorCopy(self.s.origin, self.moveinfo.start_origin);
+ Math3D.VectorCopy(dest, self.moveinfo.end_origin);
+ Move_Calc(self, dest, train_wait);
+ self.spawnflags |= TRAIN_START_ON;
+
+ }
+
+ public static EntThinkAdapter func_train_find = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent;
+
+ if (null == self.target) {
+ gi.dprintf("train_find: no target\n");
+ return true;
+ }
+ ent = G_PickTarget(self.target);
+ if (null == ent) {
+ gi.dprintf("train_find: target " + self.target + " not found\n");
+ return true;
+ }
+ self.target = ent.target;
+
+ Math3D.VectorSubtract(ent.s.origin, self.mins, self.s.origin);
+ gi.linkentity(self);
+
+ // if not triggered, start immediately
+ if (null == self.targetname)
+ self.spawnflags |= TRAIN_START_ON;
+
+ if ((self.spawnflags & TRAIN_START_ON) != 0) {
+ self.nextthink = level.time + FRAMETIME;
+ self.think = train_next;
+ self.activator = self;
+ }
+ return true;
+ }
+ };
+
+ public static EntUseAdapter train_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.activator = activator;
+
+ if ((self.spawnflags & TRAIN_START_ON) != 0) {
+ if (0 == (self.spawnflags & TRAIN_TOGGLE))
+ return;
+ self.spawnflags &= ~TRAIN_START_ON;
+ Math3D.VectorClear(self.velocity);
+ self.nextthink = 0;
+ } else {
+ if (self.target_ent != null)
+ train_resume(self);
+ else
+ train_next.think(self);
+ }
+ }
+ };
+
+ static void SP_func_train(edict_t self) {
+ self.movetype = MOVETYPE_PUSH;
+
+ Math3D.VectorClear(self.s.angles);
+ self.blocked = train_blocked;
+ if ((self.spawnflags & TRAIN_BLOCK_STOPS) != 0)
+ self.dmg = 0;
+ else {
+ if (0 == self.dmg)
+ self.dmg = 100;
+ }
+ self.solid = SOLID_BSP;
+ gi.setmodel(self, self.model);
+
+ if (st.noise != null)
+ self.moveinfo.sound_middle = gi.soundindex(st.noise);
+
+ if (0 == self.speed)
+ self.speed = 100;
+
+ self.moveinfo.speed = self.speed;
+ self.moveinfo.accel = self.moveinfo.decel = self.moveinfo.speed;
+
+ self.use = train_use;
+
+ gi.linkentity(self);
+
+ if (self.target != null) {
+ // start trains on the second frame, to make sure their targets have had
+ // a chance to spawn
+ self.nextthink = level.time + FRAMETIME;
+ self.think = func_train_find;
+ } else {
+ gi.dprintf("func_train without a target at " + Lib.vtos(self.absmin) + "\n");
+ }
+ }
+
+ /*QUAKED trigger_elevator (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
+ */
+ static EntUseAdapter trigger_elevator_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ edict_t target;
+
+ if (0 != self.movetarget.nextthink) {
+ // gi.dprintf("elevator busy\n");
+ return;
+ }
+
+ if (null == other.pathtarget) {
+ gi.dprintf("elevator used with no pathtarget\n");
+ return;
+ }
+
+ target = G_PickTarget(other.pathtarget);
+ if (null == target) {
+ gi.dprintf("elevator used with bad pathtarget: " + other.pathtarget + "\n");
+ return;
+ }
+
+ self.movetarget.target_ent = target;
+ train_resume(self.movetarget);
+ }
+ };
+
+ static EntThinkAdapter trigger_elevator_init = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (null == self.target) {
+ gi.dprintf("trigger_elevator has no target\n");
+ return true;
+ }
+ self.movetarget = G_PickTarget(self.target);
+ if (null == self.movetarget) {
+ gi.dprintf("trigger_elevator unable to find target " + self.target + "\n");
+ return true;
+ }
+ if (Lib.strcmp(self.movetarget.classname, "func_train") != 0) {
+ gi.dprintf("trigger_elevator target " + self.target + " is not a train\n");
+ return true;
+ }
+
+ self.use = trigger_elevator_use;
+ self.svflags = SVF_NOCLIENT;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter SP_trigger_elevator = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.think = trigger_elevator_init;
+ self.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+ /*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
+ "wait" base time between triggering all targets, default is 1
+ "random" wait variance, default is 0
+
+ so, the basic time between firing is a random time between
+ (wait - random) and (wait + random)
+
+ "delay" delay before first firing when turned on, default is 0
+
+ "pausetime" additional delay used only the very first time
+ and only if spawned with START_ON
+
+ These can used but not touched.
+ */
+
+ static EntThinkAdapter func_timer_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ G_UseTargets(self, self.activator);
+ self.nextthink = level.time + self.wait + Lib.crandom() * self.random;
+ return true;
+ }
+ };
+
+ static EntUseAdapter func_timer_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.activator = activator;
+
+ // if on, turn it off
+ if (self.nextthink != 0) {
+ self.nextthink = 0;
+ return;
+ }
+
+ // turn it on
+ if (self.delay != 0)
+ self.nextthink = level.time + self.delay;
+ else
+ func_timer_think.think(self);
+ }
+ };
+
+ static void SP_func_timer(edict_t self) {
+ if (0 == self.wait)
+ self.wait = 1.0f;
+
+ self.use = func_timer_use;
+ self.think = func_timer_think;
+
+ if (self.random >= self.wait) {
+ self.random = self.wait - FRAMETIME;
+ gi.dprintf("func_timer at " + Lib.vtos(self.s.origin) + " has random >= wait\n");
+ }
+
+ if ((self.spawnflags & 1) != 0) {
+ self.nextthink = level.time + 1.0f + st.pausetime + self.delay + self.wait + Lib.crandom() * self.random;
+ self.activator = self;
+ }
+
+ self.svflags = SVF_NOCLIENT;
+ }
+
+ /*QUAKED func_conveyor (0 .5 .8) ? START_ON TOGGLE
+ Conveyors are stationary brushes that move what's on them.
+ The brush should be have a surface with at least one current content enabled.
+ speed default 100
+ */
+
+ static EntUseAdapter func_conveyor_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if ((self.spawnflags & 1) != 0) {
+ self.speed = 0;
+ self.spawnflags &= ~1;
+ } else {
+ self.speed = self.count;
+ self.spawnflags |= 1;
+ }
+
+ if (0 == (self.spawnflags & 2))
+ self.count = 0;
+ }
+ };
+
+ static EntThinkAdapter SP_func_conveyor = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if (0 == self.speed)
+ self.speed = 100;
+
+ if (0 == (self.spawnflags & 1)) {
+ self.count = (int) self.speed;
+ self.speed = 0;
+ }
+
+ self.use = func_conveyor_use;
+
+ gi.setmodel(self, self.model);
+ self.solid = SOLID_BSP;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ /*QUAKED func_door_secret (0 .5 .8) ? always_shoot 1st_left 1st_down
+ A secret door. Slide back and then to the side.
+
+ open_once doors never closes
+ 1st_left 1st move is left of arrow
+ 1st_down 1st move is down from arrow
+ always_shoot door is shootebale even if targeted
+
+ "angle" determines the direction
+ "dmg" damage to inflic when blocked (default 2)
+ "wait" how long to hold in the open position (default 5, -1 means hold)
+ */
+
+ public final static int SECRET_ALWAYS_SHOOT = 1;
+ public final static int SECRET_1ST_LEFT = 2;
+ public final static int SECRET_1ST_DOWN = 4;
+
+ static EntUseAdapter door_secret_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ // make sure we're not already moving
+ if (0 == Math3D.VectorCompare(self.s.origin, vec3_origin))
+ return;
+
+ Move_Calc(self, self.pos1, door_secret_move1);
+ door_use_areaportals(self, true);
+ }
+ };
+
+ static EntThinkAdapter door_secret_move1 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.nextthink = level.time + 1.0f;
+ self.think = door_secret_move2;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_secret_move2 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Move_Calc(self, self.pos2, door_secret_move3);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_secret_move3 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.wait == -1)
+ return true;
+ self.nextthink = level.time + self.wait;
+ self.think = door_secret_move4;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_secret_move4 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Move_Calc(self, self.pos1, door_secret_move5);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_secret_move5 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.nextthink = level.time + 1.0f;
+ self.think = door_secret_move6;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_secret_move6 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ Move_Calc(self, vec3_origin, door_secret_done);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter door_secret_done = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (null == (self.targetname) || 0 != (self.spawnflags & SECRET_ALWAYS_SHOOT)) {
+ self.health = 0;
+ self.takedamage = DAMAGE_YES;
+ }
+ door_use_areaportals(self, false);
+ return true;
+ }
+ };
+
+ static EntBlockedAdapter door_secret_blocked = new EntBlockedAdapter() {
+
+ public void blocked(edict_t self, edict_t other) {
+ if (0 == (other.svflags & SVF_MONSTER) && (null == other.client)) {
+ // give it a chance to go away on it's own terms (like gibs)
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
+ // if it's still there, nuke it
+ if (other != null)
+ BecomeExplosion1(other);
+ return;
+ }
+
+ if (level.time < self.touch_debounce_time)
+ return;
+ self.touch_debounce_time = level.time + 0.5f;
+
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, self.dmg, 1, 0, MOD_CRUSH);
+ }
+ };
+
+ static EntDieAdapter door_secret_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ self.takedamage = DAMAGE_NO;
+ door_secret_use.use(self, attacker, attacker);
+ }
+ };
+
+ static EntThinkAdapter SP_func_door_secret = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] forward={0,0,0}, right={0,0,0}, up={0,0,0};
+ float side;
+ float width;
+ float length;
+
+ ent.moveinfo.sound_start = gi.soundindex("doors/dr1_strt.wav");
+ ent.moveinfo.sound_middle = gi.soundindex("doors/dr1_mid.wav");
+ ent.moveinfo.sound_end = gi.soundindex("doors/dr1_end.wav");
+
+ ent.movetype = MOVETYPE_PUSH;
+ ent.solid = SOLID_BSP;
+ gi.setmodel(ent, ent.model);
+
+ ent.blocked = door_secret_blocked;
+ ent.use = door_secret_use;
+
+ if (null == (ent.targetname) || 0 != (ent.spawnflags & SECRET_ALWAYS_SHOOT)) {
+ ent.health = 0;
+ ent.takedamage = DAMAGE_YES;
+ ent.die = door_secret_die;
+ }
+
+ if (0 == ent.dmg)
+ ent.dmg = 2;
+
+ if (0 == ent.wait)
+ ent.wait = 5;
+
+ ent.moveinfo.accel = ent.moveinfo.decel = ent.moveinfo.speed = 50;
+
+ // calculate positions
+ Math3D.AngleVectors(ent.s.angles, forward, right, up);
+ Math3D.VectorClear(ent.s.angles);
+ side = 1.0f - (ent.spawnflags & SECRET_1ST_LEFT);
+ if ((ent.spawnflags & SECRET_1ST_DOWN) != 0)
+ width = Math.abs(Math3D.DotProduct(up, ent.size));
+ else
+ width = Math.abs(Math3D.DotProduct(right, ent.size));
+ length = Math.abs(Math3D.DotProduct(forward, ent.size));
+ if ((ent.spawnflags & SECRET_1ST_DOWN) != 0)
+ Math3D.VectorMA(ent.s.origin, -1 * width, up, ent.pos1);
+ else
+ Math3D.VectorMA(ent.s.origin, side * width, right, ent.pos1);
+ Math3D.VectorMA(ent.pos1, length, forward, ent.pos2);
+
+ if (ent.health != 0) {
+ ent.takedamage = DAMAGE_YES;
+ ent.die = door_killed;
+ ent.max_health = ent.health;
+ } else if (ent.targetname != null && ent.message != null) {
+ gi.soundindex("misc/talk.wav");
+ ent.touch = door_touch;
+ }
+
+ ent.classname = "func_door";
+
+ gi.linkentity(ent);
+ return true;
+ }
+ };
+
+ /*QUAKED func_killbox (1 0 0) ?
+ Kills everything inside when fired, irrespective of protection.
+ */
+ static EntUseAdapter use_killbox = new EntUseAdapter() {
+ void use_killbox(edict_t self, edict_t other, edict_t activator) {
+ KillBox(self);
+ }
+ };
+
+ static EntThinkAdapter SP_func_killbox = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ gi.setmodel(ent, ent.model);
+ ent.use = use_killbox;
+ ent.svflags = SVF_NOCLIENT;
+ return true;
+ }
+ };
+
+
+
+
+
+}
diff --git a/src/jake2/game/GameMisc.java b/src/jake2/game/GameMisc.java
new file mode 100644
index 0000000..a269c15
--- /dev/null
+++ b/src/jake2/game/GameMisc.java
@@ -0,0 +1,1583 @@
+/*
+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 27.12.2003 by RST.
+// $Id: GameMisc.java,v 1.1 2004-07-07 19:58:59 hzi Exp $
+
+package jake2.game;
+
+import java.util.Date;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class GameMisc extends GameTrigger {
+
+ /*QUAKED func_group (0 0 0) ?
+ Used to group brushes together just for editor convenience.
+ */
+
+ //=====================================================
+
+ static EntUseAdapter Use_Areaportal = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ ent.count ^= 1; // toggle state
+ // gi.dprintf ("portalstate: %i = %i\n", ent.style, ent.count);
+ gi.SetAreaPortalState(ent.style, ent.count!=0);
+ }
+ };
+
+ /*QUAKED func_areaportal (0 0 0) ?
+
+ This is a non-visible object that divides the world into
+ areas that are seperated when this portal is not activated.
+ Usually enclosed in the middle of a door.
+ */
+
+ static EntThinkAdapter SP_func_areaportal = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ ent.use = Use_Areaportal;
+ ent.count = 0; // always start closed;
+ return true;
+ }
+ };
+
+ /*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
+ Target: next path corner
+ Pathtarget: gets used when an entity that has
+ this path_corner targeted touches it
+ */
+ static EntTouchAdapter path_corner_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ float[] v={0,0,0};
+ edict_t next;
+
+ if (other.movetarget != self)
+ return;
+
+ if (other.enemy != null)
+ return;
+
+ if (self.pathtarget != null) {
+ String savetarget;
+
+ savetarget = self.target;
+ self.target = self.pathtarget;
+ G_UseTargets(self, other);
+ self.target = savetarget;
+ }
+
+ if (self.target != null)
+ next = G_PickTarget(self.target);
+ else
+ next = null;
+
+ if ((next != null) && (next.spawnflags & 1) != 0) {
+ VectorCopy(next.s.origin, v);
+ v[2] += next.mins[2];
+ v[2] -= other.mins[2];
+ VectorCopy(v, other.s.origin);
+ next = G_PickTarget(next.target);
+ other.s.event = EV_OTHER_TELEPORT;
+ }
+
+ other.goalentity = other.movetarget = next;
+
+ if (self.wait != 0) {
+ other.monsterinfo.pausetime = level.time + self.wait;
+ other.monsterinfo.stand.think(other);
+ return;
+ }
+
+ if (other.movetarget == null) {
+ other.monsterinfo.pausetime = level.time + 100000000;
+ other.monsterinfo.stand.think(other);
+ }
+ else {
+ VectorSubtract(other.goalentity.s.origin, other.s.origin, v);
+ other.ideal_yaw = vectoyaw(v);
+ }
+ }
+ };
+
+ public static void SP_path_corner(edict_t self) {
+ if (self.targetname == null) {
+ gi.dprintf("path_corner with no targetname at " + vtos(self.s.origin) + "\n");
+ G_FreeEdict(self);
+ return;
+ }
+
+ self.solid = SOLID_TRIGGER;
+ self.touch = path_corner_touch;
+ VectorSet(self.mins, -8, -8, -8);
+ VectorSet(self.maxs, 8, 8, 8);
+ self.svflags |= SVF_NOCLIENT;
+ gi.linkentity(self);
+ }
+
+ /*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold
+ Makes this the target of a monster and it will head here
+ when first activated before going after the activator. If
+ hold is selected, it will stay here.
+ */
+ static EntTouchAdapter point_combat_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ edict_t activator;
+
+ if (other.movetarget != self)
+ return;
+
+ if (self.target != null) {
+ other.target = self.target;
+ other.goalentity = other.movetarget = G_PickTarget(other.target);
+ if (null == other.goalentity) {
+ gi.dprintf(self.classname + " at " + vtos(self.s.origin) + " target " + self.target + " does not exist\n");
+ other.movetarget = self;
+ }
+ self.target = null;
+ }
+ else if ((self.spawnflags & 1) != 0 && 0 == (other.flags & (FL_SWIM | FL_FLY))) {
+ other.monsterinfo.pausetime = level.time + 100000000;
+ other.monsterinfo.aiflags |= AI_STAND_GROUND;
+ other.monsterinfo.stand.think(other);
+ }
+
+ if (other.movetarget == self) {
+ other.target = null;
+ other.movetarget = null;
+ other.goalentity = other.enemy;
+ other.monsterinfo.aiflags &= ~AI_COMBAT_POINT;
+ }
+
+ if (self.pathtarget != null) {
+ String savetarget;
+
+ savetarget = self.target;
+ self.target = self.pathtarget;
+ if (other.enemy != null && other.enemy.client != null)
+ activator = other.enemy;
+ else if (other.oldenemy != null && other.oldenemy.client != null)
+ activator = other.oldenemy;
+ else if (other.activator != null && other.activator.client != null)
+ activator = other.activator;
+ else
+ activator = other;
+ G_UseTargets(self, activator);
+ self.target = savetarget;
+ }
+ }
+ };
+
+ public static void SP_point_combat(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+ self.solid = SOLID_TRIGGER;
+ self.touch = point_combat_touch;
+ VectorSet(self.mins, -8, -8, -16);
+ VectorSet(self.maxs, 8, 8, 16);
+ self.svflags = SVF_NOCLIENT;
+ gi.linkentity(self);
+ };
+
+ /*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
+ Just for the debugging level. Don't use
+ */
+ public static EntThinkAdapter TH_viewthing = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ ent.s.frame = (ent.s.frame + 1) % 7;
+ ent.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+ public static void SP_viewthing(edict_t ent) {
+ gi.dprintf("viewthing spawned\n");
+
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ ent.s.renderfx = RF_FRAMELERP;
+ VectorSet(ent.mins, -16, -16, -24);
+ VectorSet(ent.maxs, 16, 16, 32);
+ ent.s.modelindex = gi.modelindex("models/objects/banner/tris.md2");
+ gi.linkentity(ent);
+ ent.nextthink = level.time + 0.5f;
+ ent.think = TH_viewthing;
+ return;
+ }
+
+ /*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
+ Used as a positional target for spotlights, etc.
+ */
+ public static void SP_info_null(edict_t self) {
+ G_FreeEdict(self);
+ };
+
+ /*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
+ Used as a positional target for lightning.
+ */
+ public static void SP_info_notnull(edict_t self) {
+ VectorCopy(self.s.origin, self.absmin);
+ VectorCopy(self.s.origin, self.absmax);
+ };
+
+ /*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
+ Non-displayed light.
+ Default light value is 300.
+ Default style is 0.
+ If targeted, will toggle between on and off.
+ Default _cone value is 10 (used to set size of light for spotlights)
+ */
+
+ public static final int START_OFF = 1;
+
+ static EntUseAdapter light_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if ((self.spawnflags & START_OFF) != 0) {
+ gi.configstring(CS_LIGHTS + self.style, "m");
+ self.spawnflags &= ~START_OFF;
+ }
+ else {
+ gi.configstring(CS_LIGHTS + self.style, "a");
+ self.spawnflags |= START_OFF;
+ }
+ }
+ };
+
+ public static void SP_light(edict_t self) {
+ // no targeted lights in deathmatch, because they cause global messages
+ if (null == self.targetname || deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ if (self.style >= 32) {
+ self.use = light_use;
+ if ((self.spawnflags & START_OFF) != 0)
+ gi.configstring(CS_LIGHTS + self.style, "a");
+ else
+ gi.configstring(CS_LIGHTS + self.style, "m");
+ }
+ }
+
+ /*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST
+ This is just a solid wall if not inhibited
+
+ TRIGGER_SPAWN the wall will not be present until triggered
+ it will then blink in to existance; it will
+ kill anything that was in it's way
+
+ TOGGLE only valid for TRIGGER_SPAWN walls
+ this allows the wall to be turned on and off
+
+ START_ON only valid for TRIGGER_SPAWN walls
+ the wall will initially be present
+ */
+
+ static EntUseAdapter func_wall_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (self.solid == SOLID_NOT) {
+ self.solid = SOLID_BSP;
+ self.svflags &= ~SVF_NOCLIENT;
+ KillBox(self);
+ }
+ else {
+ self.solid = SOLID_NOT;
+ self.svflags |= SVF_NOCLIENT;
+ }
+ gi.linkentity(self);
+
+ if (0 == (self.spawnflags & 2))
+ self.use = null;
+ }
+ };
+
+ public static void SP_func_wall(edict_t self) {
+ self.movetype = MOVETYPE_PUSH;
+ gi.setmodel(self, self.model);
+
+ if ((self.spawnflags & 8) != 0)
+ self.s.effects |= EF_ANIM_ALL;
+ if ((self.spawnflags & 16) != 0)
+ self.s.effects |= EF_ANIM_ALLFAST;
+
+ // just a wall
+ if ((self.spawnflags & 7) == 0) {
+ self.solid = SOLID_BSP;
+ gi.linkentity(self);
+ return;
+ }
+
+ // it must be TRIGGER_SPAWN
+ if (0 == (self.spawnflags & 1)) {
+ // gi.dprintf("func_wall missing TRIGGER_SPAWN\n");
+ self.spawnflags |= 1;
+ }
+
+ // yell if the spawnflags are odd
+ if ((self.spawnflags & 4) != 0) {
+ if (0 == (self.spawnflags & 2)) {
+ gi.dprintf("func_wall START_ON without TOGGLE\n");
+ self.spawnflags |= 2;
+ }
+ }
+
+ self.use = func_wall_use;
+ if ((self.spawnflags & 4) != 0) {
+ self.solid = SOLID_BSP;
+ }
+ else {
+ self.solid = SOLID_NOT;
+ self.svflags |= SVF_NOCLIENT;
+ }
+ gi.linkentity(self);
+ }
+
+ /*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST
+ This is solid bmodel that will fall if it's support it removed.
+ */
+ static EntTouchAdapter func_object_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ // only squash thing we fall on top of
+ if (plane == null)
+ return;
+ if (plane.normal[2] < 1.0)
+ return;
+ if (other.takedamage == DAMAGE_NO)
+ return;
+ T_Damage(other, self, self, vec3_origin, self.s.origin, vec3_origin, self.dmg, 1, 0, MOD_CRUSH);
+ }
+ };
+
+ static EntThinkAdapter func_object_release = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.movetype = MOVETYPE_TOSS;
+ self.touch = func_object_touch;
+ return true;
+ }
+ };
+
+ static EntUseAdapter func_object_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.solid = SOLID_BSP;
+ self.svflags &= ~SVF_NOCLIENT;
+ self.use = null;
+ KillBox(self);
+ func_object_release.think(self);
+ }
+ };
+
+ public static void SP_func_object(edict_t self) {
+ gi.setmodel(self, self.model);
+
+ self.mins[0] += 1;
+ self.mins[1] += 1;
+ self.mins[2] += 1;
+ self.maxs[0] -= 1;
+ self.maxs[1] -= 1;
+ self.maxs[2] -= 1;
+
+ if (self.dmg == 0)
+ self.dmg = 100;
+
+ if (self.spawnflags == 0) {
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_PUSH;
+ self.think = func_object_release;
+ self.nextthink = level.time + 2 * FRAMETIME;
+ }
+ else {
+ self.solid = SOLID_NOT;
+ self.movetype = MOVETYPE_PUSH;
+ self.use = func_object_use;
+ self.svflags |= SVF_NOCLIENT;
+ }
+
+ if ((self.spawnflags & 2) != 0)
+ self.s.effects |= EF_ANIM_ALL;
+ if ((self.spawnflags & 4) != 0)
+ self.s.effects |= EF_ANIM_ALLFAST;
+
+ self.clipmask = MASK_MONSTERSOLID;
+
+ gi.linkentity(self);
+ }
+
+ /*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST
+ Any brush that you want to explode or break apart. If you want an
+ ex0plosion, set dmg and it will do a radius explosion of that amount
+ at the center of the bursh.
+
+ If targeted it will not be shootable.
+
+ health defaults to 100.
+
+ mass defaults to 75. This determines how much debris is emitted when
+ it explodes. You get one large chunk per 100 of mass (up to 8) and
+ one small chunk per 25 of mass (up to 16). So 800 gives the most.
+ */
+ static EntDieAdapter func_explosive_explode = new EntDieAdapter() {
+
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ float[] origin={0,0,0};
+ float[] chunkorigin={0,0,0};
+ float[] size={0,0,0};
+ int count;
+ int mass;
+
+ // bmodel origins are (0 0 0), we need to adjust that here
+ VectorScale(self.size, 0.5f, size);
+ VectorAdd(self.absmin, size, origin);
+ VectorCopy(origin, self.s.origin);
+
+ self.takedamage = DAMAGE_NO;
+
+ if (self.dmg != 0)
+ T_RadiusDamage(self, attacker, self.dmg, null, self.dmg + 40, MOD_EXPLOSIVE);
+
+ VectorSubtract(self.s.origin, inflictor.s.origin, self.velocity);
+ VectorNormalize(self.velocity);
+ VectorScale(self.velocity, 150, self.velocity);
+
+ // start chunks towards the center
+ VectorScale(size, 0.5f, size);
+
+ mass = self.mass;
+ if (0 == mass)
+ mass = 75;
+
+ // big chunks
+ if (mass >= 100) {
+ count = mass / 100;
+ if (count > 8)
+ count = 8;
+ while (count-- != 0) {
+ chunkorigin[0] = origin[0] + crandom() * size[0];
+ chunkorigin[1] = origin[1] + crandom() * size[1];
+ chunkorigin[2] = origin[2] + crandom() * size[2];
+ ThrowDebris(self, "models/objects/debris1/tris.md2", 1, chunkorigin);
+ }
+ }
+
+ // small chunks
+ count = mass / 25;
+ if (count > 16)
+ count = 16;
+ while (count-- != 0) {
+ chunkorigin[0] = origin[0] + crandom() * size[0];
+ chunkorigin[1] = origin[1] + crandom() * size[1];
+ chunkorigin[2] = origin[2] + crandom() * size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", 2, chunkorigin);
+ }
+
+ G_UseTargets(self, attacker);
+
+ if (self.dmg != 0)
+ BecomeExplosion1(self);
+ else
+ G_FreeEdict(self);
+ }
+ };
+
+ static EntUseAdapter func_explosive_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ func_explosive_explode.die(self, self, other, self.health, vec3_origin);
+ }
+ };
+
+ static EntUseAdapter func_explosive_spawn = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.solid = SOLID_BSP;
+ self.svflags &= ~SVF_NOCLIENT;
+ self.use = null;
+ KillBox(self);
+ gi.linkentity(self);
+ }
+ };
+
+ public static void SP_func_explosive(edict_t self) {
+ if (deathmatch.value != 0) { // auto-remove for deathmatch
+ G_FreeEdict(self);
+ return;
+ }
+
+ self.movetype = MOVETYPE_PUSH;
+
+ gi.modelindex("models/objects/debris1/tris.md2");
+ gi.modelindex("models/objects/debris2/tris.md2");
+
+ gi.setmodel(self, self.model);
+
+ if ((self.spawnflags & 1) != 0) {
+ self.svflags |= SVF_NOCLIENT;
+ self.solid = SOLID_NOT;
+ self.use = func_explosive_spawn;
+ }
+ else {
+ self.solid = SOLID_BSP;
+ if (self.targetname != null)
+ self.use = func_explosive_use;
+ }
+
+ if ((self.spawnflags & 2) != 0)
+ self.s.effects |= EF_ANIM_ALL;
+ if ((self.spawnflags & 4) != 0)
+ self.s.effects |= EF_ANIM_ALLFAST;
+
+ if (self.use != func_explosive_use) {
+ if (self.health == 0)
+ self.health = 100;
+ self.die = func_explosive_explode;
+ self.takedamage = DAMAGE_YES;
+ }
+
+ gi.linkentity(self);
+ }
+
+ /*QUAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40)
+ Large exploding box. You can override its mass (100),
+ health (80), and dmg (150).
+ */
+
+ static EntTouchAdapter barrel_touch = new EntTouchAdapter() {
+
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ float ratio;
+ float[] v={0,0,0};
+
+ if ((null == other.groundentity) || (other.groundentity == self))
+ return;
+
+ ratio = (float) other.mass / (float) self.mass;
+ VectorSubtract(self.s.origin, other.s.origin, v);
+ M.M_walkmove(self, vectoyaw(v), 20 * ratio * FRAMETIME);
+ }
+ };
+
+ static EntThinkAdapter barrel_explode = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] org={0,0,0};
+ float spd;
+ float[] save={0,0,0};
+
+ T_RadiusDamage(self, self.activator, self.dmg, null, self.dmg + 40, MOD_BARREL);
+
+ VectorCopy(self.s.origin, save);
+ VectorMA(self.absmin, 0.5f, self.size, self.s.origin);
+
+ // a few big chunks
+ spd = 1.5f * (float) self.dmg / 200.0f;
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org);
+
+ // bottom corners
+ spd = 1.75f * (float) self.dmg / 200.0f;
+ VectorCopy(self.absmin, org);
+ ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
+ VectorCopy(self.absmin, org);
+ org[0] += self.size[0];
+ ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
+ VectorCopy(self.absmin, org);
+ org[1] += self.size[1];
+ ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
+ VectorCopy(self.absmin, org);
+ org[0] += self.size[0];
+ org[1] += self.size[1];
+ ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
+
+ // a bunch of little chunks
+ spd = 2 * self.dmg / 200;
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+ org[0] = self.s.origin[0] + crandom() * self.size[0];
+ org[1] = self.s.origin[1] + crandom() * self.size[1];
+ org[2] = self.s.origin[2] + crandom() * self.size[2];
+ ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
+
+ VectorCopy(save, self.s.origin);
+ if (self.groundentity != null)
+ BecomeExplosion2(self);
+ else
+ BecomeExplosion1(self);
+
+ return true;
+ }
+ };
+
+ static EntDieAdapter barrel_delay = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+
+ self.takedamage = DAMAGE_NO;
+ self.nextthink = level.time + 2 * FRAMETIME;
+ self.think = barrel_explode;
+ self.activator = attacker;
+ }
+ };
+
+ public static void SP_misc_explobox(edict_t self) {
+ if (deathmatch.value != 0) { // auto-remove for deathmatch
+ G_FreeEdict(self);
+ return;
+ }
+
+ gi.modelindex("models/objects/debris1/tris.md2");
+ gi.modelindex("models/objects/debris2/tris.md2");
+ gi.modelindex("models/objects/debris3/tris.md2");
+
+ self.solid = SOLID_BBOX;
+ self.movetype = MOVETYPE_STEP;
+
+ self.model = "models/objects/barrels/tris.md2";
+ self.s.modelindex = gi.modelindex(self.model);
+ VectorSet(self.mins, -16, -16, 0);
+ VectorSet(self.maxs, 16, 16, 40);
+
+ if (self.mass == 0)
+ self.mass = 400;
+ if (0 == self.health)
+ self.health = 10;
+ if (0 == self.dmg)
+ self.dmg = 150;
+
+ self.die = barrel_delay;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.aiflags = AI_NOSTEP;
+
+ self.touch = barrel_touch;
+
+ self.think = M.M_droptofloor;
+ self.nextthink = level.time + 2 * FRAMETIME;
+
+ gi.linkentity(self);
+ }
+
+ //
+ // miscellaneous specialty items
+ //
+
+ /*QUAKED misc_blackhole (1 .5 0) (-8 -8 -8) (8 8 8)
+ */
+
+ static EntUseAdapter misc_blackhole_use = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ /*
+ gi.WriteByte (svc_temp_entity);
+ gi.WriteByte (TE_BOSSTPORT);
+ gi.WritePosition (ent.s.origin);
+ gi.multicast (ent.s.origin, MULTICAST_PVS);
+ */
+ G_FreeEdict(ent);
+ }
+ };
+
+ static EntThinkAdapter misc_blackhole_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if (++self.s.frame < 19)
+ self.nextthink = level.time + FRAMETIME;
+ else {
+ self.s.frame = 0;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ return true;
+ }
+ };
+
+ public static void SP_misc_blackhole(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_NOT;
+ VectorSet(ent.mins, -64, -64, 0);
+ VectorSet(ent.maxs, 64, 64, 8);
+ ent.s.modelindex = gi.modelindex("models/objects/black/tris.md2");
+ ent.s.renderfx = RF_TRANSLUCENT;
+ ent.use = misc_blackhole_use;
+ ent.think = misc_blackhole_think;
+ ent.nextthink = level.time + 2 * FRAMETIME;
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_eastertank (1 .5 0) (-32 -32 -16) (32 32 32)
+ */
+
+ static EntThinkAdapter misc_eastertank_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (++self.s.frame < 293)
+ self.nextthink = level.time + FRAMETIME;
+ else {
+ self.s.frame = 254;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ return true;
+ }
+ };
+
+ public static void SP_misc_eastertank(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ VectorSet(ent.mins, -32, -32, -16);
+ VectorSet(ent.maxs, 32, 32, 32);
+ ent.s.modelindex = gi.modelindex("models/monsters/tank/tris.md2");
+ ent.s.frame = 254;
+ ent.think = misc_eastertank_think;
+ ent.nextthink = level.time + 2 * FRAMETIME;
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_easterchick (1 .5 0) (-32 -32 0) (32 32 32)
+ */
+
+ static EntThinkAdapter misc_easterchick_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (++self.s.frame < 247)
+ self.nextthink = level.time + FRAMETIME;
+ else {
+ self.s.frame = 208;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ return true;
+ }
+ };
+
+ public static void SP_misc_easterchick(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ VectorSet(ent.mins, -32, -32, 0);
+ VectorSet(ent.maxs, 32, 32, 32);
+ ent.s.modelindex = gi.modelindex("models/monsters/bitch/tris.md2");
+ ent.s.frame = 208;
+ ent.think = misc_easterchick_think;
+ ent.nextthink = level.time + 2 * FRAMETIME;
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_easterchick2 (1 .5 0) (-32 -32 0) (32 32 32)
+ */
+ static EntThinkAdapter misc_easterchick2_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (++self.s.frame < 287)
+ self.nextthink = level.time + FRAMETIME;
+ else {
+ self.s.frame = 248;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ return true;
+ }
+ };
+
+ public static void SP_misc_easterchick2(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ VectorSet(ent.mins, -32, -32, 0);
+ VectorSet(ent.maxs, 32, 32, 32);
+ ent.s.modelindex = gi.modelindex("models/monsters/bitch/tris.md2");
+ ent.s.frame = 248;
+ ent.think = misc_easterchick2_think;
+ ent.nextthink = level.time + 2 * FRAMETIME;
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED monster_commander_body (1 .5 0) (-32 -32 0) (32 32 48)
+ Not really a monster, this is the Tank Commander's decapitated body.
+ There should be a item_commander_head that has this as it's target.
+ */
+
+ static EntThinkAdapter commander_body_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (++self.s.frame < 24)
+ self.nextthink = level.time + FRAMETIME;
+ else
+ self.nextthink = 0;
+
+ if (self.s.frame == 22)
+ gi.sound(self, CHAN_BODY, gi.soundindex("tank/thud.wav"), 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntUseAdapter commander_body_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.think = commander_body_think;
+ self.nextthink = level.time + FRAMETIME;
+ gi.sound(self, CHAN_BODY, gi.soundindex("tank/pain.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+
+ static EntThinkAdapter commander_body_drop = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.movetype = MOVETYPE_TOSS;
+ self.s.origin[2] += 2;
+ return true;
+ }
+ };
+
+ public static void SP_monster_commander_body(edict_t self) {
+ self.movetype = MOVETYPE_NONE;
+ self.solid = SOLID_BBOX;
+ self.model = "models/monsters/commandr/tris.md2";
+ self.s.modelindex = gi.modelindex(self.model);
+ VectorSet(self.mins, -32, -32, 0);
+ VectorSet(self.maxs, 32, 32, 48);
+ self.use = commander_body_use;
+ self.takedamage = DAMAGE_YES;
+ self.flags = FL_GODMODE;
+ self.s.renderfx |= RF_FRAMELERP;
+ gi.linkentity(self);
+
+ gi.soundindex("tank/thud.wav");
+ gi.soundindex("tank/pain.wav");
+
+ self.think = commander_body_drop;
+ self.nextthink = level.time + 5 * FRAMETIME;
+ }
+
+ /*QUAKED misc_banner (1 .5 0) (-4 -4 -4) (4 4 4)
+ The origin is the bottom of the banner.
+ The banner is 128 tall.
+ */
+ static EntThinkAdapter misc_banner_think = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ ent.s.frame = (ent.s.frame + 1) % 16;
+ ent.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+ public static void SP_misc_banner(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_NOT;
+ ent.s.modelindex = gi.modelindex("models/objects/banner/tris.md2");
+ ent.s.frame = rand() % 16;
+ gi.linkentity(ent);
+
+ ent.think = misc_banner_think;
+ ent.nextthink = level.time + FRAMETIME;
+ }
+
+ /*QUAKED misc_deadsoldier (1 .5 0) (-16 -16 0) (16 16 16) ON_BACK ON_STOMACH BACK_DECAP FETAL_POS SIT_DECAP IMPALED
+ This is the dead player model. Comes in 6 exciting different poses!
+ */
+ static EntDieAdapter misc_deadsoldier_die = new EntDieAdapter() {
+
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ if (self.health > -80)
+ return;
+
+ gi.sound(self, CHAN_BODY, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ }
+ };
+
+ public static void SP_misc_deadsoldier(edict_t ent) {
+ if (deathmatch.value != 0) { // auto-remove for deathmatch
+ G_FreeEdict(ent);
+ return;
+ }
+
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ ent.s.modelindex = gi.modelindex("models/deadbods/dude/tris.md2");
+
+ // Defaults to frame 0
+ if ((ent.spawnflags & 2) != 0)
+ ent.s.frame = 1;
+ else if ((ent.spawnflags & 4) != 0)
+ ent.s.frame = 2;
+ else if ((ent.spawnflags & 8) != 0)
+ ent.s.frame = 3;
+ else if ((ent.spawnflags & 16) != 0)
+ ent.s.frame = 4;
+ else if ((ent.spawnflags & 32) != 0)
+ ent.s.frame = 5;
+ else
+ ent.s.frame = 0;
+
+ VectorSet(ent.mins, -16, -16, 0);
+ VectorSet(ent.maxs, 16, 16, 16);
+ ent.deadflag = DEAD_DEAD;
+ ent.takedamage = DAMAGE_YES;
+ ent.svflags |= SVF_MONSTER | SVF_DEADMONSTER;
+ ent.die = misc_deadsoldier_die;
+ ent.monsterinfo.aiflags |= AI_GOOD_GUY;
+
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_viper (1 .5 0) (-16 -16 0) (16 16 32)
+ This is the Viper for the flyby bombing.
+ It is trigger_spawned, so you must have something use it for it to show up.
+ There must be a path for it to follow once it is activated.
+
+ "speed" How fast the Viper should fly
+ */
+
+ static EntUseAdapter misc_viper_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.svflags &= ~SVF_NOCLIENT;
+ self.use = GameFunc.train_use;
+ GameFunc.train_use.use(self, other, activator);
+ }
+ };
+
+ public static void SP_misc_viper(edict_t ent) {
+ if (null == ent.target) {
+ gi.dprintf("misc_viper without a target at " + vtos(ent.absmin) + "\n");
+ G_FreeEdict(ent);
+ return;
+ }
+
+ if (0 == ent.speed)
+ ent.speed = 300;
+
+ ent.movetype = MOVETYPE_PUSH;
+ ent.solid = SOLID_NOT;
+ ent.s.modelindex = gi.modelindex("models/ships/viper/tris.md2");
+ VectorSet(ent.mins, -16, -16, 0);
+ VectorSet(ent.maxs, 16, 16, 32);
+
+ ent.think = GameFunc.func_train_find;
+ ent.nextthink = level.time + FRAMETIME;
+ ent.use = misc_viper_use;
+ ent.svflags |= SVF_NOCLIENT;
+ ent.moveinfo.accel = ent.moveinfo.decel = ent.moveinfo.speed = ent.speed;
+
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_bigviper (1 .5 0) (-176 -120 -24) (176 120 72)
+ This is a large stationary viper as seen in Paul's intro
+ */
+ public static void SP_misc_bigviper(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ VectorSet(ent.mins, -176, -120, -24);
+ VectorSet(ent.maxs, 176, 120, 72);
+ ent.s.modelindex = gi.modelindex("models/ships/bigviper/tris.md2");
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_viper_bomb (1 0 0) (-8 -8 -8) (8 8 8)
+ "dmg" how much boom should the bomb make?
+ */
+ static EntTouchAdapter misc_viper_bomb_touch = new EntTouchAdapter() {
+
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ G_UseTargets(self, self.activator);
+
+ self.s.origin[2] = self.absmin[2] + 1;
+ T_RadiusDamage(self, self, self.dmg, null, self.dmg + 40, MOD_BOMB);
+ BecomeExplosion2(self);
+ }
+ };
+
+ static EntThinkAdapter misc_viper_bomb_prethink = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] v={0,0,0};
+ float diff;
+
+ self.groundentity = null;
+
+ diff = self.timestamp - level.time;
+ if (diff < -1.0)
+ diff = -1.0f;
+
+ VectorScale(self.moveinfo.dir, 1.0f + diff, v);
+ v[2] = diff;
+
+ diff = self.s.angles[2];
+ vectoangles(v, self.s.angles);
+ self.s.angles[2] = diff + 10;
+
+ return true;
+ }
+ };
+
+ static EntUseAdapter misc_viper_bomb_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ edict_t viper=null;
+
+ self.solid = SOLID_BBOX;
+ self.svflags &= ~SVF_NOCLIENT;
+ self.s.effects |= EF_ROCKET;
+ self.use = null;
+ self.movetype = MOVETYPE_TOSS;
+ self.prethink = misc_viper_bomb_prethink;
+ self.touch = misc_viper_bomb_touch;
+ self.activator = activator;
+
+ EdictIterator es = null;
+
+ es = G_Find(es, findByClass, "misc_viper");
+ if (es != null)
+ viper = es.o;
+
+ VectorScale(viper.moveinfo.dir, viper.moveinfo.speed, self.velocity);
+
+ self.timestamp = level.time;
+ VectorCopy(viper.moveinfo.dir, self.moveinfo.dir);
+ }
+ };
+
+ public static void SP_misc_viper_bomb(edict_t self) {
+ self.movetype = MOVETYPE_NONE;
+ self.solid = SOLID_NOT;
+ VectorSet(self.mins, -8, -8, -8);
+ VectorSet(self.maxs, 8, 8, 8);
+
+ self.s.modelindex = gi.modelindex("models/objects/bomb/tris.md2");
+
+ if (self.dmg == 0)
+ self.dmg = 1000;
+
+ self.use = misc_viper_bomb_use;
+ self.svflags |= SVF_NOCLIENT;
+
+ gi.linkentity(self);
+ }
+
+ /*QUAKED misc_strogg_ship (1 .5 0) (-16 -16 0) (16 16 32)
+ This is a Storgg ship for the flybys.
+ It is trigger_spawned, so you must have something use it for it to show up.
+ There must be a path for it to follow once it is activated.
+
+ "speed" How fast it should fly
+ */
+
+ static EntUseAdapter misc_strogg_ship_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.svflags &= ~SVF_NOCLIENT;
+ self.use = GameFunc.train_use;
+ GameFunc.train_use.use(self, other, activator);
+ }
+ };
+
+ public static void SP_misc_strogg_ship(edict_t ent) {
+ if (null == ent.target) {
+ gi.dprintf(ent.classname + " without a target at " + vtos(ent.absmin) + "\n");
+ G_FreeEdict(ent);
+ return;
+ }
+
+ if (0 == ent.speed)
+ ent.speed = 300;
+
+ ent.movetype = MOVETYPE_PUSH;
+ ent.solid = SOLID_NOT;
+ ent.s.modelindex = gi.modelindex("models/ships/strogg1/tris.md2");
+ VectorSet(ent.mins, -16, -16, 0);
+ VectorSet(ent.maxs, 16, 16, 32);
+
+ ent.think = GameFunc.func_train_find;
+ ent.nextthink = level.time + FRAMETIME;
+ ent.use = misc_strogg_ship_use;
+ ent.svflags |= SVF_NOCLIENT;
+ ent.moveinfo.accel = ent.moveinfo.decel = ent.moveinfo.speed = ent.speed;
+
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_satellite_dish (1 .5 0) (-64 -64 0) (64 64 128)
+ */
+ static EntThinkAdapter misc_satellite_dish_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.s.frame++;
+ if (self.s.frame < 38)
+ self.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+ static EntUseAdapter misc_satellite_dish_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.s.frame = 0;
+ self.think = misc_satellite_dish_think;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ };
+
+ public static void SP_misc_satellite_dish(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ VectorSet(ent.mins, -64, -64, 0);
+ VectorSet(ent.maxs, 64, 64, 128);
+ ent.s.modelindex = gi.modelindex("models/objects/satellite/tris.md2");
+ ent.use = misc_satellite_dish_use;
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12)
+ */
+ public static void SP_light_mine1(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ ent.s.modelindex = gi.modelindex("models/objects/minelite/light1/tris.md2");
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12)
+ */
+ public static void SP_light_mine2(edict_t ent) {
+ ent.movetype = MOVETYPE_NONE;
+ ent.solid = SOLID_BBOX;
+ ent.s.modelindex = gi.modelindex("models/objects/minelite/light2/tris.md2");
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8)
+ Intended for use with the target_spawner
+ */
+ public static void SP_misc_gib_arm(edict_t ent) {
+ gi.setmodel(ent, "models/objects/gibs/arm/tris.md2");
+ ent.solid = SOLID_NOT;
+ ent.s.effects |= EF_GIB;
+ ent.takedamage = DAMAGE_YES;
+ ent.die = gib_die;
+ ent.movetype = MOVETYPE_TOSS;
+ ent.svflags |= SVF_MONSTER;
+ ent.deadflag = DEAD_DEAD;
+ ent.avelocity[0] = random() * 200;
+ ent.avelocity[1] = random() * 200;
+ ent.avelocity[2] = random() * 200;
+ ent.think = G_FreeEdictA;
+ ent.nextthink = level.time + 30;
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8)
+ Intended for use with the target_spawner
+ */
+ public static void SP_misc_gib_leg(edict_t ent) {
+ gi.setmodel(ent, "models/objects/gibs/leg/tris.md2");
+ ent.solid = SOLID_NOT;
+ ent.s.effects |= EF_GIB;
+ ent.takedamage = DAMAGE_YES;
+ ent.die = gib_die;
+ ent.movetype = MOVETYPE_TOSS;
+ ent.svflags |= SVF_MONSTER;
+ ent.deadflag = DEAD_DEAD;
+ ent.avelocity[0] = random() * 200;
+ ent.avelocity[1] = random() * 200;
+ ent.avelocity[2] = random() * 200;
+ ent.think = G_FreeEdictA;
+ ent.nextthink = level.time + 30;
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8)
+ Intended for use with the target_spawner
+ */
+ public static void SP_misc_gib_head(edict_t ent) {
+ gi.setmodel(ent, "models/objects/gibs/head/tris.md2");
+ ent.solid = SOLID_NOT;
+ ent.s.effects |= EF_GIB;
+ ent.takedamage = DAMAGE_YES;
+ ent.die = gib_die;
+ ent.movetype = MOVETYPE_TOSS;
+ ent.svflags |= SVF_MONSTER;
+ ent.deadflag = DEAD_DEAD;
+ ent.avelocity[0] = random() * 200;
+ ent.avelocity[1] = random() * 200;
+ ent.avelocity[2] = random() * 200;
+ ent.think = G_FreeEdictA;
+ ent.nextthink = level.time + 30;
+ gi.linkentity(ent);
+ }
+
+ //=====================================================
+
+ /*QUAKED target_character (0 0 1) ?
+ used with target_string (must be on same "team")
+ "count" is position in the string (starts at 1)
+ */
+
+ public static void SP_target_character(edict_t self) {
+ self.movetype = MOVETYPE_PUSH;
+ gi.setmodel(self, self.model);
+ self.solid = SOLID_BSP;
+ self.s.frame = 12;
+ gi.linkentity(self);
+ return;
+ }
+
+ /*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8)
+ */
+
+ static EntUseAdapter target_string_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ edict_t e;
+ int n, l;
+ char c;
+
+ l = strlen(self.message);
+ for (e = self.teammaster; e != null; e = e.teamchain) {
+ if (e.count == 0)
+ continue;
+ n = e.count - 1;
+ if (n > l) {
+ e.s.frame = 12;
+ continue;
+ }
+
+ c = self.message.charAt(n);
+ if (c >= '0' && c <= '9')
+ e.s.frame = c - '0';
+ else if (c == '-')
+ e.s.frame = 10;
+ else if (c == ':')
+ e.s.frame = 11;
+ else
+ e.s.frame = 12;
+ }
+ }
+ };
+
+ public static void SP_target_string(edict_t self) {
+ if (self.message == null)
+ self.message = "";
+ self.use = target_string_use;
+ }
+
+ /*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE
+ target a target_string with this
+
+ The default is to be a time of day clock
+
+ TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget"
+ If START_OFF, this entity must be used before it starts
+
+ "style" 0 "xx"
+ 1 "xx:xx"
+ 2 "xx:xx:xx"
+ */
+
+ public static final int CLOCK_MESSAGE_SIZE = 16;
+
+ // don't let field width of any clock messages change, or it
+ // could cause an overwrite after a game load
+
+ public static void func_clock_reset(edict_t self) {
+ self.activator = null;
+ if ((self.spawnflags & 1) != 0) {
+ self.health = 0;
+ self.wait = self.count;
+ }
+ else if ((self.spawnflags & 2) != 0) {
+ self.health = self.count;
+ self.wait = 0;
+ }
+ }
+
+ public static void func_clock_format_countdown(edict_t self) {
+ if (self.style == 0) {
+ self.message = "" + self.health;
+ //Com_sprintf(self.message, CLOCK_MESSAGE_SIZE, "%2i", self.health);
+ return;
+ }
+
+ if (self.style == 1) {
+ self.message = "" + self.health / 60 + ":" + self.health % 60;
+ //Com_sprintf(self.message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self.health / 60, self.health % 60);
+ /*
+ if (self.message.charAt(3) == ' ')
+ self.message.charAt(3) = '0';
+ */
+ return;
+ }
+
+ if (self.style == 2) {
+ self.message = "" + self.health / 3600 + ":" + (self.health - (self.health / 3600) * 3600) / 60 + ":" + self.health % 60;
+ /*
+ Com_sprintf(
+ self.message,
+ CLOCK_MESSAGE_SIZE,
+ "%2i:%2i:%2i",
+ self.health / 3600,
+ (self.health - (self.health / 3600) * 3600) / 60,
+ self.health % 60);
+ if (self.message[3] == ' ')
+ self.message[3] = '0';
+ if (self.message[6] == ' ')
+ self.message[6] = '0';
+ */
+ return;
+ }
+ }
+
+ public static EntThinkAdapter func_clock_think = new EntThinkAdapter() {
+
+ public boolean think(edict_t self) {
+ if (null == self.enemy) {
+
+ EdictIterator es = null;
+
+ es = G_Find(es, findByTarget, self.target);
+ if (es != null)
+ self.enemy = es.o;
+ if (self.enemy == null)
+ return true;
+ }
+
+ if ((self.spawnflags & 1) != 0) {
+ func_clock_format_countdown(self);
+ self.health++;
+ }
+ else if ((self.spawnflags & 2) != 0) {
+ func_clock_format_countdown(self);
+ self.health--;
+ }
+ else {
+ Date d = new Date();
+ self.message = "" + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
+
+ /*
+ struct tm * ltime;
+ time_t gmtime;
+
+ time(& gmtime);
+ ltime = localtime(& gmtime);
+ Com_sprintf(self.message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
+ if (self.message[3] == ' ')
+ self.message[3] = '0';
+ if (self.message[6] == ' ')
+ self.message[6] = '0';
+ */
+ }
+
+ self.enemy.message = self.message;
+ self.enemy.use.use(self.enemy, self, self);
+
+ if (((self.spawnflags & 1) != 0 && (self.health > self.wait))
+ || ((self.spawnflags & 2) != 0 && (self.health < self.wait))) {
+ if (self.pathtarget != null) {
+ String savetarget;
+ String savemessage;
+
+ savetarget = self.target;
+ savemessage = self.message;
+ self.target = self.pathtarget;
+ self.message = null;
+ G_UseTargets(self, self.activator);
+ self.target = savetarget;
+ self.message = savemessage;
+ }
+
+ if (0 == (self.spawnflags & 8))
+ return true;
+
+ func_clock_reset(self);
+
+ if ((self.spawnflags & 4) != 0)
+ return true;
+ }
+
+ self.nextthink = level.time + 1;
+ return true;
+
+ }
+ };
+
+ static EntUseAdapter func_clock_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (0 == (self.spawnflags & 8))
+ self.use = null;
+ if (self.activator!=null)
+ return;
+ self.activator = activator;
+ self.think.think(self);
+ }
+ };
+
+ public static void SP_func_clock(edict_t self) {
+ if (self.target == null) {
+ gi.dprintf(self.classname + " with no target at " + vtos(self.s.origin) + "\n");
+ G_FreeEdict(self);
+ return;
+ }
+
+ if ((self.spawnflags & 2) != 0 && (0 == self.count)) {
+ gi.dprintf(self.classname + " with no count at " + vtos(self.s.origin) + "\n");
+ G_FreeEdict(self);
+ return;
+ }
+
+ if ((self.spawnflags & 1) != 0 && (0 == self.count))
+ self.count = 60 * 60;
+
+ func_clock_reset(self);
+
+ //self.message = gi.TagMalloc(CLOCK_MESSAGE_SIZE, TAG_LEVEL);
+ self.message = new String();
+
+ self.think = func_clock_think;
+
+ if ((self.spawnflags & 4) != 0)
+ self.use = func_clock_use;
+ else
+ self.nextthink = level.time + 1;
+ }
+
+ //=================================================================================
+
+ static EntTouchAdapter teleporter_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ edict_t dest;
+ int i;
+
+ if (other.client ==null)
+ return;
+
+ EdictIterator es =null;
+ dest = G_Find(null, findByTarget, self.target).o;
+
+ if (dest==null) {
+ gi.dprintf("Couldn't find destination\n");
+ return;
+ }
+
+ // unlink to make sure it can't possibly interfere with KillBox
+ gi.unlinkentity(other);
+
+ VectorCopy(dest.s.origin, other.s.origin);
+ VectorCopy(dest.s.origin, other.s.old_origin);
+ other.s.origin[2] += 10;
+
+ // clear the velocity and hold them in place briefly
+ VectorClear(other.velocity);
+ other.client.ps.pmove.pm_time = 160 >> 3; // hold time
+ other.client.ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
+
+ // draw the teleport splash at source and on the player
+ self.owner.s.event = EV_PLAYER_TELEPORT;
+ other.s.event = EV_PLAYER_TELEPORT;
+
+ // set angles
+ for (i = 0; i < 3; i++) {
+ other.client.ps.pmove.delta_angles[i] = (short) ANGLE2SHORT(dest.s.angles[i] - other.client.resp.cmd_angles[i]);
+ }
+
+ VectorClear(other.s.angles);
+ VectorClear(other.client.ps.viewangles);
+ VectorClear(other.client.v_angle);
+
+ // kill anything at the destination
+ KillBox(other);
+
+ gi.linkentity(other);
+ }
+ };
+
+ /*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16)
+ Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object.
+ */
+ public static void SP_misc_teleporter(edict_t ent) {
+ edict_t trig;
+
+ if (ent.target==null) {
+ gi.dprintf("teleporter without a target.\n");
+ G_FreeEdict(ent);
+ return;
+ }
+
+ gi.setmodel(ent, "models/objects/dmspot/tris.md2");
+ ent.s.skinnum = 1;
+ ent.s.effects = EF_TELEPORTER;
+ ent.s.sound = gi.soundindex("world/amb10.wav");
+ ent.solid = SOLID_BBOX;
+
+ VectorSet(ent.mins, -32, -32, -24);
+ VectorSet(ent.maxs, 32, 32, -16);
+ gi.linkentity(ent);
+
+ trig = G_Spawn();
+ trig.touch = teleporter_touch;
+ trig.solid = SOLID_TRIGGER;
+ trig.target = ent.target;
+ trig.owner = ent;
+ VectorCopy(ent.s.origin, trig.s.origin);
+ VectorSet(trig.mins, -8, -8, 8);
+ VectorSet(trig.maxs, 8, 8, 24);
+ gi.linkentity(trig);
+
+ }
+
+ /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
+ Point teleporters at these.
+ */
+
+ public static EntThinkAdapter SP_misc_teleporter_dest = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ gi.setmodel(ent, "models/objects/dmspot/tris.md2");
+ ent.s.skinnum = 0;
+ ent.solid = SOLID_BBOX;
+ // ent.s.effects |= EF_FLIES;
+ VectorSet(ent.mins, -32, -32, -24);
+ VectorSet(ent.maxs, 32, 32, -16);
+ gi.linkentity(ent);
+ return true;
+ }
+ };
+
+}
diff --git a/src/jake2/game/GamePWeapon.java b/src/jake2/game/GamePWeapon.java
new file mode 100644
index 0000000..7d845f0
--- /dev/null
+++ b/src/jake2/game/GamePWeapon.java
@@ -0,0 +1,1437 @@
+/*
+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 16.11.2003 by RST.
+// $Id: GamePWeapon.java,v 1.1 2004-07-07 19:59:00 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class GamePWeapon extends M_Player {
+
+ static boolean is_quad;
+ static byte is_silenced;
+
+ static void P_ProjectSource(
+ gclient_t client,
+ float[] point,
+ float[] distance,
+ float[] forward,
+ float[] right,
+ float[] result) {
+ float[] _distance= { 0, 0, 0 };
+
+ Math3D.VectorCopy(distance, _distance);
+ if (client.pers.hand == LEFT_HANDED)
+ _distance[1] *= -1;
+ else if (client.pers.hand == CENTER_HANDED)
+ _distance[1]= 0;
+ Math3D.G_ProjectSource(point, _distance, forward, right, result);
+ }
+
+ static EntInteractAdapter Pickup_Weapon= new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+ int index;
+ gitem_t ammo;
+
+ index= ITEM_INDEX(ent.item);
+
+ if ((((int) (dmflags.value) & DF_WEAPONS_STAY) != 0 || coop.value != 0)
+ && 0 != other.client.pers.inventory[index]) {
+ if (0 == (ent.spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)))
+ return false; // leave the weapon for others to pickup
+ }
+
+ other.client.pers.inventory[index]++;
+
+ if (0 == (ent.spawnflags & DROPPED_ITEM)) {
+ // give them some ammo with it
+ ammo= FindItem(ent.item.ammo);
+ if (((int) dmflags.value & DF_INFINITE_AMMO) != 0)
+ Add_Ammo(other, ammo, 1000);
+ else
+ Add_Ammo(other, ammo, ammo.quantity);
+
+ if (0 == (ent.spawnflags & DROPPED_PLAYER_ITEM)) {
+ if (deathmatch.value != 0) {
+ if (((int) (dmflags.value) & DF_WEAPONS_STAY) != 0)
+ ent.flags |= FL_RESPAWN;
+ else
+ SetRespawn(ent, 30);
+ }
+ if (coop.value != 0)
+ ent.flags |= FL_RESPAWN;
+ }
+ }
+
+ if (other.client.pers.weapon != ent.item
+ && (other.client.pers.inventory[index] == 1)
+ && (0 == deathmatch.value || other.client.pers.weapon == FindItem("blaster")))
+ other.client.newweapon= ent.item;
+
+ return true;
+ }
+ };
+
+ /*
+ ===============
+ ChangeWeapon
+
+ The old weapon has been dropped all the way, so make the new one
+ current
+ ===============
+ */
+ static void ChangeWeapon(edict_t ent) {
+ int i;
+
+ if (ent.client.grenade_time != 0) {
+ ent.client.grenade_time= level.time;
+ ent.client.weapon_sound= 0;
+ weapon_grenade_fire(ent, false);
+ ent.client.grenade_time= 0;
+ }
+
+ ent.client.pers.lastweapon= ent.client.pers.weapon;
+ ent.client.pers.weapon= ent.client.newweapon;
+ ent.client.newweapon= null;
+ ent.client.machinegun_shots= 0;
+
+ // set visible model
+ if (ent.s.modelindex == 255) {
+ if (ent.client.pers.weapon != null)
+ i= ((ent.client.pers.weapon.weapmodel & 0xff) << 8);
+ else
+ i= 0;
+ //ent.s.skinnum = (ent - g_edicts - 1) | i;
+ ent.s.skinnum= (ent.index - 1) | i;
+ }
+
+ if (ent.client.pers.weapon != null && ent.client.pers.weapon.ammo != null)
+ ent.client.ammo_index= ITEM_INDEX(FindItem(ent.client.pers.weapon.ammo));
+ else
+ ent.client.ammo_index= 0;
+
+ if (ent.client.pers.weapon == null) { // dead
+ ent.client.ps.gunindex= 0;
+ return;
+ }
+
+ ent.client.weaponstate= WEAPON_ACTIVATING;
+ ent.client.ps.gunframe= 0;
+ ent.client.ps.gunindex= gi.modelindex(ent.client.pers.weapon.view_model);
+
+ ent.client.anim_priority= ANIM_PAIN;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.s.frame= FRAME_crpain1;
+ ent.client.anim_end= FRAME_crpain4;
+ } else {
+ ent.s.frame= FRAME_pain301;
+ ent.client.anim_end= FRAME_pain304;
+
+ }
+ }
+
+ /*
+ =================
+ NoAmmoWeaponChange
+ =================
+ */
+ static void NoAmmoWeaponChange(edict_t ent) {
+ if (0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("slugs"))]
+ && 0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("railgun"))]) {
+ ent.client.newweapon= FindItem("railgun");
+ return;
+ }
+ if (0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("cells"))]
+ && 0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))]) {
+ ent.client.newweapon= FindItem("hyperblaster");
+ return;
+ }
+ if (0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("bullets"))]
+ && 0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("chaingun"))]) {
+ ent.client.newweapon= FindItem("chaingun");
+ return;
+ }
+ if (0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("bullets"))]
+ && 0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("machinegun"))]) {
+ ent.client.newweapon= FindItem("machinegun");
+ return;
+ }
+ if (ent.client.pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
+ && 0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("super shotgun"))]) {
+ ent.client.newweapon= FindItem("super shotgun");
+ return;
+ }
+ if (0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("shells"))]
+ && 0 != ent.client.pers.inventory[ITEM_INDEX(FindItem("shotgun"))]) {
+ ent.client.newweapon= FindItem("shotgun");
+ return;
+ }
+ ent.client.newweapon= FindItem("blaster");
+ }
+
+ /*
+ =================
+ Think_Weapon
+
+ Called by ClientBeginServerFrame and ClientThink
+ =================
+ */
+ static void Think_Weapon(edict_t ent) {
+ // if just died, put the weapon away
+ if (ent.health < 1) {
+ ent.client.newweapon= null;
+ ChangeWeapon(ent);
+ }
+
+ // call active weapon think routine
+ if (null != ent.client.pers.weapon && null != ent.client.pers.weapon.weaponthink) {
+ is_quad= (ent.client.quad_framenum > level.framenum);
+ if (ent.client.silencer_shots != 0)
+ is_silenced= (byte) MZ_SILENCED;
+ else
+ is_silenced= 0;
+ ent.client.pers.weapon.weaponthink.think(ent);
+ }
+ }
+
+ /*
+ ================
+ Use_Weapon
+
+ Make the weapon ready if there is ammo
+ ================
+ */
+ static ItemUseAdapter Use_Weapon= new ItemUseAdapter() {
+
+ public void use(edict_t ent, gitem_t item) {
+ int ammo_index;
+ gitem_t ammo_item;
+
+ // see if we're already using it
+ if (item == ent.client.pers.weapon)
+ return;
+
+ if (item.ammo != null && 0 == g_select_empty.value && 0 == (item.flags & IT_AMMO)) {
+ ammo_item= FindItem(item.ammo);
+ ammo_index= ITEM_INDEX(ammo_item);
+
+ if (0 == ent.client.pers.inventory[ammo_index]) {
+ gi.cprintf(ent, PRINT_HIGH, "No " + ammo_item.pickup_name + " for " + ".\n");
+ return;
+ }
+
+ if (ent.client.pers.inventory[ammo_index] < item.quantity) {
+ gi.cprintf(
+ ent,
+ PRINT_HIGH,
+ "Not enough " + ammo_item.pickup_name + " for " + item.pickup_name + ".\n");
+ return;
+ }
+ }
+
+ // change to this weapon when down
+ ent.client.newweapon= item;
+ }
+ };
+
+ /*
+ ================
+ Drop_Weapon
+ ================
+ */
+
+ static ItemDropAdapter Drop_Weapon= new ItemDropAdapter() {
+ public void drop(edict_t ent, gitem_t item) {
+ int index;
+
+ if (0 != ((int) (dmflags.value) & DF_WEAPONS_STAY))
+ return;
+
+ index= ITEM_INDEX(item);
+ // see if we're already using it
+ if (((item == ent.client.pers.weapon) || (item == ent.client.newweapon))
+ && (ent.client.pers.inventory[index] == 1)) {
+ gi.cprintf(ent, PRINT_HIGH, "Can't drop current weapon\n");
+ return;
+ }
+
+ Drop_Item(ent, item);
+ ent.client.pers.inventory[index]--;
+ }
+ };
+
+ /*
+ ================
+ Weapon_Generic
+
+ A generic function to handle the basics of weapon thinking
+ ================
+ */
+
+ static void Weapon_Generic(
+ edict_t ent,
+ int FRAME_ACTIVATE_LAST,
+ int FRAME_FIRE_LAST,
+ int FRAME_IDLE_LAST,
+ int FRAME_DEACTIVATE_LAST,
+ int pause_frames[],
+ int fire_frames[],
+ EntThinkAdapter fire) {
+ int FRAME_FIRE_FIRST= (FRAME_ACTIVATE_LAST + 1);
+ int FRAME_IDLE_FIRST= (FRAME_FIRE_LAST + 1);
+ int FRAME_DEACTIVATE_FIRST= (FRAME_IDLE_LAST + 1);
+
+ int n;
+
+ if (ent.deadflag != 0 || ent.s.modelindex != 255) // VWep animations screw up corpses
+ {
+ return;
+ }
+
+ if (ent.client.weaponstate == WEAPON_DROPPING) {
+ if (ent.client.ps.gunframe == FRAME_DEACTIVATE_LAST) {
+ ChangeWeapon(ent);
+ return;
+ } else if ((FRAME_DEACTIVATE_LAST - ent.client.ps.gunframe) == 4) {
+ ent.client.anim_priority= ANIM_REVERSE;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.s.frame= FRAME_crpain4 + 1;
+ ent.client.anim_end= FRAME_crpain1;
+ } else {
+ ent.s.frame= FRAME_pain304 + 1;
+ ent.client.anim_end= FRAME_pain301;
+
+ }
+ }
+
+ ent.client.ps.gunframe++;
+ return;
+ }
+
+ if (ent.client.weaponstate == WEAPON_ACTIVATING) {
+ if (ent.client.ps.gunframe == FRAME_ACTIVATE_LAST) {
+ ent.client.weaponstate= WEAPON_READY;
+ ent.client.ps.gunframe= FRAME_IDLE_FIRST;
+ return;
+ }
+
+ ent.client.ps.gunframe++;
+ return;
+ }
+
+ if ((ent.client.newweapon != null) && (ent.client.weaponstate != WEAPON_FIRING)) {
+ ent.client.weaponstate= WEAPON_DROPPING;
+ ent.client.ps.gunframe= FRAME_DEACTIVATE_FIRST;
+
+ if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4) {
+ ent.client.anim_priority= ANIM_REVERSE;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.s.frame= FRAME_crpain4 + 1;
+ ent.client.anim_end= FRAME_crpain1;
+ } else {
+ ent.s.frame= FRAME_pain304 + 1;
+ ent.client.anim_end= FRAME_pain301;
+
+ }
+ }
+ return;
+ }
+
+ if (ent.client.weaponstate == WEAPON_READY) {
+ if (((ent.client.latched_buttons | ent.client.buttons) & BUTTON_ATTACK) != 0) {
+ ent.client.latched_buttons &= ~BUTTON_ATTACK;
+ if ((0 != ent.client.ammo_index)
+ || (ent.client.pers.inventory[ent.client.ammo_index]
+ >= ent.client.pers.weapon.quantity)) {
+ ent.client.ps.gunframe= FRAME_FIRE_FIRST;
+ ent.client.weaponstate= WEAPON_FIRING;
+
+ // start the animation
+ ent.client.anim_priority= ANIM_ATTACK;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.s.frame= FRAME_crattak1 - 1;
+ ent.client.anim_end= FRAME_crattak9;
+ } else {
+ ent.s.frame= FRAME_attack1 - 1;
+ ent.client.anim_end= FRAME_attack8;
+ }
+ } else {
+ if (level.time >= ent.pain_debounce_time) {
+ gi.sound(
+ ent,
+ CHAN_VOICE,
+ gi.soundindex("weapons/noammo.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ ent.pain_debounce_time= level.time + 1;
+ }
+ NoAmmoWeaponChange(ent);
+ }
+ } else {
+ if (ent.client.ps.gunframe == FRAME_IDLE_LAST) {
+ ent.client.ps.gunframe= FRAME_IDLE_FIRST;
+ return;
+ }
+
+ if (pause_frames != null) {
+ for (n= 0; pause_frames[n] != 0; n++) {
+ if (ent.client.ps.gunframe == pause_frames[n]) {
+ if ((Lib.rand() & 15) != 0)
+ return;
+ }
+ }
+ }
+
+ ent.client.ps.gunframe++;
+ return;
+ }
+ }
+
+ if (ent.client.weaponstate == WEAPON_FIRING) {
+ for (n= 0; fire_frames[n] != 0; n++) {
+ if (ent.client.ps.gunframe == fire_frames[n]) {
+ if (ent.client.quad_framenum > level.framenum)
+ gi.sound(
+ ent,
+ CHAN_ITEM,
+ gi.soundindex("items/damage3.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+
+ fire.think(ent);
+ break;
+ }
+ }
+
+ if (0 == fire_frames[n])
+ ent.client.ps.gunframe++;
+
+ if (ent.client.ps.gunframe == FRAME_IDLE_FIRST + 1)
+ ent.client.weaponstate= WEAPON_READY;
+ }
+ }
+
+ /*
+ ======================================================================
+
+ GRENADE
+
+ ======================================================================
+ */
+
+ static void weapon_grenade_fire(edict_t ent, boolean held) {
+ float[] offset= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+ int damage= 125;
+ float timer;
+ int speed;
+ float radius;
+
+ radius= damage + 40;
+ if (is_quad)
+ damage *= 4;
+
+ Math3D.VectorSet(offset, 8, 8, ent.viewheight - 8);
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+
+ timer= ent.client.grenade_time - level.time;
+ speed=
+ (int) (GRENADE_MINSPEED
+ + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER));
+ Fire.fire_grenade2(ent, start, forward, damage, speed, timer, radius, held);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index]--;
+
+ ent.client.grenade_time= level.time + 1.0f;
+
+ if (ent.deadflag != 0 || ent.s.modelindex != 255) // VWep animations screw up corpses
+ {
+ return;
+ }
+
+ if (ent.health <= 0)
+ return;
+
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.client.anim_priority= ANIM_ATTACK;
+ ent.s.frame= FRAME_crattak1 - 1;
+ ent.client.anim_end= FRAME_crattak3;
+ } else {
+ ent.client.anim_priority= ANIM_REVERSE;
+ ent.s.frame= FRAME_wave08;
+ ent.client.anim_end= FRAME_wave01;
+ }
+ }
+
+ static EntThinkAdapter Weapon_Grenade= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+ if ((ent.client.newweapon != null) && (ent.client.weaponstate == WEAPON_READY)) {
+ ChangeWeapon(ent);
+ return true;
+ }
+
+ if (ent.client.weaponstate == WEAPON_ACTIVATING) {
+ ent.client.weaponstate= WEAPON_READY;
+ ent.client.ps.gunframe= 16;
+ return true;
+ }
+
+ if (ent.client.weaponstate == WEAPON_READY) {
+ if (((ent.client.latched_buttons | ent.client.buttons) & BUTTON_ATTACK) != 0) {
+ ent.client.latched_buttons &= ~BUTTON_ATTACK;
+ if (0 != ent.client.pers.inventory[ent.client.ammo_index]) {
+ ent.client.ps.gunframe= 1;
+ ent.client.weaponstate= WEAPON_FIRING;
+ ent.client.grenade_time= 0;
+ } else {
+ if (level.time >= ent.pain_debounce_time) {
+ gi.sound(
+ ent,
+ CHAN_VOICE,
+ gi.soundindex("weapons/noammo.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ ent.pain_debounce_time= level.time + 1;
+ }
+ NoAmmoWeaponChange(ent);
+ }
+ return true;
+ }
+
+ if ((ent.client.ps.gunframe == 29)
+ || (ent.client.ps.gunframe == 34)
+ || (ent.client.ps.gunframe == 39)
+ || (ent.client.ps.gunframe == 48)) {
+ if ((Lib.rand() & 15) != 0)
+ return true;
+ }
+
+ if (++ent.client.ps.gunframe > 48)
+ ent.client.ps.gunframe= 16;
+ return true;
+ }
+
+ if (ent.client.weaponstate == WEAPON_FIRING) {
+ if (ent.client.ps.gunframe == 5)
+ gi.sound(
+ ent,
+ CHAN_WEAPON,
+ gi.soundindex("weapons/hgrena1b.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+
+ if (ent.client.ps.gunframe == 11) {
+ if (0 == ent.client.grenade_time) {
+ ent.client.grenade_time= level.time + GRENADE_TIMER + 0.2f;
+ ent.client.weapon_sound= gi.soundindex("weapons/hgrenc1b.wav");
+ }
+
+ // they waited too long, detonate it in their hand
+ if (!ent.client.grenade_blew_up && level.time >= ent.client.grenade_time) {
+ ent.client.weapon_sound= 0;
+ weapon_grenade_fire(ent, true);
+ ent.client.grenade_blew_up= true;
+ }
+
+ if ((ent.client.buttons & BUTTON_ATTACK) != 0)
+ return true;
+
+ if (ent.client.grenade_blew_up) {
+ if (level.time >= ent.client.grenade_time) {
+ ent.client.ps.gunframe= 15;
+ ent.client.grenade_blew_up= false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ if (ent.client.ps.gunframe == 12) {
+ ent.client.weapon_sound= 0;
+ weapon_grenade_fire(ent, false);
+ }
+
+ if ((ent.client.ps.gunframe == 15) && (level.time < ent.client.grenade_time))
+ return true;
+
+ ent.client.ps.gunframe++;
+
+ if (ent.client.ps.gunframe == 16) {
+ ent.client.grenade_time= 0;
+ ent.client.weaponstate= WEAPON_READY;
+ }
+ }
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ GRENADE LAUNCHER
+
+ ======================================================================
+ */
+
+ static EntThinkAdapter weapon_grenadelauncher_fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+ float[] offset= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+ int damage= 120;
+ float radius;
+
+ radius= damage + 40;
+ if (is_quad)
+ damage *= 4;
+
+ Math3D.VectorSet(offset, 8, 8, ent.viewheight - 8);
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+
+ Math3D.VectorScale(forward, -2, ent.client.kick_origin);
+ ent.client.kick_angles[0]= -1;
+
+ Fire.fire_grenade(ent, start, forward, damage, 600, 2.5f, radius);
+
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_GRENADE | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ ent.client.ps.gunframe++;
+
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index]--;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_GrenadeLauncher= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 34, 51, 59, 0 };
+ int fire_frames[]= { 6, 0 };
+
+ Weapon_Generic(
+ ent,
+ 5,
+ 16,
+ 59,
+ 64,
+ pause_frames,
+ fire_frames,
+ weapon_grenadelauncher_fire);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ ROCKET
+
+ ======================================================================
+ */
+
+ static EntThinkAdapter Weapon_RocketLauncher_Fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ float[] offset= { 0, 0, 0 }, start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ int damage;
+ float damage_radius;
+ int radius_damage;
+
+ damage= 100 + (int) (Lib.random() * 20.0);
+ radius_damage= 120;
+ damage_radius= 120;
+ if (is_quad) {
+ damage *= 4;
+ radius_damage *= 4;
+ }
+
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+
+ Math3D.VectorScale(forward, -2, ent.client.kick_origin);
+ ent.client.kick_angles[0]= -1;
+
+ Math3D.VectorSet(offset, 8, 8, ent.viewheight - 8);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+ Fire.fire_rocket(ent, start, forward, damage, 650, damage_radius, radius_damage);
+
+ // send muzzle flash
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_ROCKET | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ ent.client.ps.gunframe++;
+
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index]--;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_RocketLauncher= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 25, 33, 42, 50, 0 };
+ int fire_frames[]= { 5, 0 };
+
+ Weapon_Generic(
+ ent,
+ 4,
+ 12,
+ 50,
+ 54,
+ pause_frames,
+ fire_frames,
+ Weapon_RocketLauncher_Fire);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ BLASTER / HYPERBLASTER
+
+ ======================================================================
+ */
+
+ static void Blaster_Fire(
+ edict_t ent,
+ float[] g_offset,
+ int damage,
+ boolean hyper,
+ int effect) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+ float[] offset= { 0, 0, 0 };
+
+ if (is_quad)
+ damage *= 4;
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+ Math3D.VectorSet(offset, 24, 8, ent.viewheight - 8);
+ Math3D.VectorAdd(offset, g_offset, offset);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+
+ Math3D.VectorScale(forward, -2, ent.client.kick_origin);
+ ent.client.kick_angles[0]= -1;
+
+ Fire.fire_blaster(ent, start, forward, damage, 1000, effect, hyper);
+
+ // send muzzle flash
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ if (hyper)
+ gi.WriteByte(MZ_HYPERBLASTER | is_silenced);
+ else
+ gi.WriteByte(MZ_BLASTER | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+ }
+
+ static EntThinkAdapter Weapon_Blaster_Fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ int damage;
+
+ if (deathmatch.value != 0)
+ damage= 15;
+ else
+ damage= 10;
+ Blaster_Fire(ent, vec3_origin, damage, false, EF_BLASTER);
+ ent.client.ps.gunframe++;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_Blaster= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 19, 32, 0 };
+ int fire_frames[]= { 5, 0 };
+
+ Weapon_Generic(ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_HyperBlaster_Fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+ float rotation;
+ float[] offset= { 0, 0, 0 };
+ int effect;
+ int damage;
+
+ ent.client.weapon_sound= gi.soundindex("weapons/hyprbl1a.wav");
+
+ if (0 == (ent.client.buttons & BUTTON_ATTACK)) {
+ ent.client.ps.gunframe++;
+ } else {
+ if (0 == ent.client.pers.inventory[ent.client.ammo_index]) {
+ if (level.time >= ent.pain_debounce_time) {
+ gi.sound(
+ ent,
+ CHAN_VOICE,
+ gi.soundindex("weapons/noammo.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ ent.pain_debounce_time= level.time + 1;
+ }
+ NoAmmoWeaponChange(ent);
+ } else {
+ rotation= (float) ((ent.client.ps.gunframe - 5) * 2 * Math.PI / 6);
+ offset[0]= (float) (-4 * Math.sin(rotation));
+ offset[1]= 0f;
+ offset[2]= (float) (4 * Math.cos(rotation));
+
+ if ((ent.client.ps.gunframe == 6) || (ent.client.ps.gunframe == 9))
+ effect= EF_HYPERBLASTER;
+ else
+ effect= 0;
+ if (deathmatch.value != 0)
+ damage= 15;
+ else
+ damage= 20;
+ Blaster_Fire(ent, offset, damage, true, effect);
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index]--;
+
+ ent.client.anim_priority= ANIM_ATTACK;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.s.frame= FRAME_crattak1 - 1;
+ ent.client.anim_end= FRAME_crattak9;
+ } else {
+ ent.s.frame= FRAME_attack1 - 1;
+ ent.client.anim_end= FRAME_attack8;
+ }
+ }
+
+ ent.client.ps.gunframe++;
+ if (ent.client.ps.gunframe == 12
+ && 0 != ent.client.pers.inventory[ent.client.ammo_index])
+ ent.client.ps.gunframe= 6;
+ }
+
+ if (ent.client.ps.gunframe == 12) {
+ gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
+ ent.client.weapon_sound= 0;
+ }
+
+ return true;
+
+ }
+ };
+
+ static EntThinkAdapter Weapon_HyperBlaster= new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 0 };
+ int fire_frames[]= { 6, 7, 8, 9, 10, 11, 0 };
+
+ Weapon_Generic(ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ MACHINEGUN / CHAINGUN
+
+ ======================================================================
+ */
+
+ static EntThinkAdapter Machinegun_Fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ int i;
+ float[] start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] angles= { 0, 0, 0 };
+ int damage= 8;
+ int kick= 2;
+ float[] offset= { 0, 0, 0 };
+
+ if (0 == (ent.client.buttons & BUTTON_ATTACK)) {
+ ent.client.machinegun_shots= 0;
+ ent.client.ps.gunframe++;
+ return true;
+ }
+
+ if (ent.client.ps.gunframe == 5)
+ ent.client.ps.gunframe= 4;
+ else
+ ent.client.ps.gunframe= 5;
+
+ if (ent.client.pers.inventory[ent.client.ammo_index] < 1) {
+ ent.client.ps.gunframe= 6;
+ if (level.time >= ent.pain_debounce_time) {
+ gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+ ent.pain_debounce_time= level.time + 1;
+ }
+ NoAmmoWeaponChange(ent);
+ return true;
+ }
+
+ if (is_quad) {
+ damage *= 4;
+ kick *= 4;
+ }
+
+ for (i= 1; i < 3; i++) {
+ ent.client.kick_origin[i]= Lib.crandom() * 0.35f;
+ ent.client.kick_angles[i]= Lib.crandom() * 0.7f;
+ }
+ ent.client.kick_origin[0]= Lib.crandom() * 0.35f;
+ ent.client.kick_angles[0]= ent.client.machinegun_shots * -1.5f;
+
+ // raise the gun as it is firing
+ if (0 == deathmatch.value) {
+ ent.client.machinegun_shots++;
+ if (ent.client.machinegun_shots > 9)
+ ent.client.machinegun_shots= 9;
+ }
+
+ // get start / end positions
+ Math3D.VectorAdd(ent.client.v_angle, ent.client.kick_angles, angles);
+ Math3D.AngleVectors(angles, forward, right, null);
+ Math3D.VectorSet(offset, 0, 8, ent.viewheight - 8);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+ Fire.fire_bullet(
+ ent,
+ start,
+ forward,
+ damage,
+ kick,
+ DEFAULT_BULLET_HSPREAD,
+ DEFAULT_BULLET_VSPREAD,
+ MOD_MACHINEGUN);
+
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_MACHINEGUN | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index]--;
+
+ ent.client.anim_priority= ANIM_ATTACK;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.s.frame= FRAME_crattak1 - (int) (Lib.random() + 0.25);
+ ent.client.anim_end= FRAME_crattak9;
+ } else {
+ ent.s.frame= FRAME_attack1 - (int) (Lib.random() + 0.25);
+ ent.client.anim_end= FRAME_attack8;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_Machinegun= new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 23, 45, 0 };
+ int fire_frames[]= { 4, 5, 0 };
+
+ Weapon_Generic(ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Chaingun_Fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ int i;
+ int shots;
+ float[] start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, up= { 0, 0, 0 };
+ float r, u;
+ float[] offset= { 0, 0, 0 };
+ int damage;
+ int kick= 2;
+
+ if (deathmatch.value != 0)
+ damage= 6;
+ else
+ damage= 8;
+
+ if (ent.client.ps.gunframe == 5)
+ gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
+
+ if ((ent.client.ps.gunframe == 14) && 0 == (ent.client.buttons & BUTTON_ATTACK)) {
+ ent.client.ps.gunframe= 32;
+ ent.client.weapon_sound= 0;
+ return true;
+ } else if (
+ (ent.client.ps.gunframe == 21)
+ && (ent.client.buttons & BUTTON_ATTACK) != 0
+ && 0 != ent.client.pers.inventory[ent.client.ammo_index]) {
+ ent.client.ps.gunframe= 15;
+ } else {
+ ent.client.ps.gunframe++;
+ }
+
+ if (ent.client.ps.gunframe == 22) {
+ ent.client.weapon_sound= 0;
+ gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
+ } else {
+ ent.client.weapon_sound= gi.soundindex("weapons/chngnl1a.wav");
+ }
+
+ ent.client.anim_priority= ANIM_ATTACK;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ ent.s.frame= FRAME_crattak1 - (ent.client.ps.gunframe & 1);
+ ent.client.anim_end= FRAME_crattak9;
+ } else {
+ ent.s.frame= FRAME_attack1 - (ent.client.ps.gunframe & 1);
+ ent.client.anim_end= FRAME_attack8;
+ }
+
+ if (ent.client.ps.gunframe <= 9)
+ shots= 1;
+ else if (ent.client.ps.gunframe <= 14) {
+ if ((ent.client.buttons & BUTTON_ATTACK) != 0)
+ shots= 2;
+ else
+ shots= 1;
+ } else
+ shots= 3;
+
+ if (ent.client.pers.inventory[ent.client.ammo_index] < shots)
+ shots= ent.client.pers.inventory[ent.client.ammo_index];
+
+ if (0 == shots) {
+ if (level.time >= ent.pain_debounce_time) {
+ gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
+ ent.pain_debounce_time= level.time + 1;
+ }
+ NoAmmoWeaponChange(ent);
+ return true;
+ }
+
+ if (is_quad) {
+ damage *= 4;
+ kick *= 4;
+ }
+
+ for (i= 0; i < 3; i++) {
+ ent.client.kick_origin[i]= Lib.crandom() * 0.35f;
+ ent.client.kick_angles[i]= Lib.crandom() * 0.7f;
+ }
+
+ for (i= 0; i < shots; i++) {
+ // get start / end positions
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, up);
+ r= 7 + Lib.crandom() * 4;
+ u= Lib.crandom() * 4;
+ Math3D.VectorSet(offset, 0, r, u + ent.viewheight - 8);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+
+ Fire.fire_bullet(
+ ent,
+ start,
+ forward,
+ damage,
+ kick,
+ DEFAULT_BULLET_HSPREAD,
+ DEFAULT_BULLET_VSPREAD,
+ MOD_CHAINGUN);
+ }
+
+ // send muzzle flash
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte((MZ_CHAINGUN1 + shots - 1) | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index] -= shots;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_Chaingun= new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 38, 43, 51, 61, 0 };
+ int fire_frames[]= { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0 };
+
+ Weapon_Generic(ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ SHOTGUN / SUPERSHOTGUN
+
+ ======================================================================
+ */
+
+ static EntThinkAdapter weapon_shotgun_fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ float[] start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] offset= { 0, 0, 0 };
+ int damage= 4;
+ int kick= 8;
+
+ if (ent.client.ps.gunframe == 9) {
+ ent.client.ps.gunframe++;
+ return true;
+ }
+
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+
+ Math3D.VectorScale(forward, -2, ent.client.kick_origin);
+ ent.client.kick_angles[0]= -2;
+
+ Math3D.VectorSet(offset, 0, 8, ent.viewheight - 8);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+
+ if (is_quad) {
+ damage *= 4;
+ kick *= 4;
+ }
+
+ if (deathmatch.value != 0)
+ Fire.fire_shotgun(
+ ent,
+ start,
+ forward,
+ damage,
+ kick,
+ 500,
+ 500,
+ DEFAULT_DEATHMATCH_SHOTGUN_COUNT,
+ MOD_SHOTGUN);
+ else
+ Fire.fire_shotgun(
+ ent,
+ start,
+ forward,
+ damage,
+ kick,
+ 500,
+ 500,
+ DEFAULT_SHOTGUN_COUNT,
+ MOD_SHOTGUN);
+
+ // send muzzle flash
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_SHOTGUN | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ ent.client.ps.gunframe++;
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index]--;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_Shotgun= new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ int pause_frames[]= { 22, 28, 34, 0 };
+ int fire_frames[]= { 8, 9, 0 };
+
+ Weapon_Generic(ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter weapon_supershotgun_fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ float[] start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] offset= { 0, 0, 0 };
+ float[] v= { 0, 0, 0 };
+ int damage= 6;
+ int kick= 12;
+
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+
+ Math3D.VectorScale(forward, -2, ent.client.kick_origin);
+ ent.client.kick_angles[0]= -2;
+
+ Math3D.VectorSet(offset, 0, 8, ent.viewheight - 8);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+
+ if (is_quad) {
+ damage *= 4;
+ kick *= 4;
+ }
+
+ v[PITCH]= ent.client.v_angle[PITCH];
+ v[YAW]= ent.client.v_angle[YAW] - 5;
+ v[ROLL]= ent.client.v_angle[ROLL];
+ Math3D.AngleVectors(v, forward, null, null);
+ Fire.fire_shotgun(
+ ent,
+ start,
+ forward,
+ damage,
+ kick,
+ DEFAULT_SHOTGUN_HSPREAD,
+ DEFAULT_SHOTGUN_VSPREAD,
+ DEFAULT_SSHOTGUN_COUNT / 2,
+ MOD_SSHOTGUN);
+ v[YAW]= ent.client.v_angle[YAW] + 5;
+ Math3D.AngleVectors(v, forward, null, null);
+ Fire.fire_shotgun(
+ ent,
+ start,
+ forward,
+ damage,
+ kick,
+ DEFAULT_SHOTGUN_HSPREAD,
+ DEFAULT_SHOTGUN_VSPREAD,
+ DEFAULT_SSHOTGUN_COUNT / 2,
+ MOD_SSHOTGUN);
+
+ // send muzzle flash
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_SSHOTGUN | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ ent.client.ps.gunframe++;
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index] -= 2;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_SuperShotgun= new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 29, 42, 57, 0 };
+ int fire_frames[]= { 7, 0 };
+
+ Weapon_Generic(ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ RAILGUN
+
+ ======================================================================
+ */
+ static EntThinkAdapter weapon_railgun_fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ float[] start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] offset= { 0, 0, 0 };
+ int damage;
+ int kick;
+
+ if (deathmatch.value != 0) { // normal damage is too extreme in dm
+ damage= 100;
+ kick= 200;
+ } else {
+ damage= 150;
+ kick= 250;
+ }
+
+ if (is_quad) {
+ damage *= 4;
+ kick *= 4;
+ }
+
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+
+ Math3D.VectorScale(forward, -3, ent.client.kick_origin);
+ ent.client.kick_angles[0]= -3;
+
+ Math3D.VectorSet(offset, 0, 7, ent.viewheight - 8);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+ Fire.fire_rail(ent, start, forward, damage, kick);
+
+ // send muzzle flash
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_RAILGUN | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ ent.client.ps.gunframe++;
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index]--;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Weapon_Railgun= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ int pause_frames[]= { 56, 0 };
+ int fire_frames[]= { 4, 0 };
+ Weapon_Generic(ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
+ return true;
+ }
+ };
+
+ /*
+ ======================================================================
+
+ BFG10K
+
+ ======================================================================
+ */
+
+ static EntThinkAdapter weapon_bfg_fire= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ float[] offset= { 0, 0, 0 }, start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ int damage;
+ float damage_radius= 1000;
+
+ if (deathmatch.value != 0)
+ damage= 200;
+ else
+ damage= 500;
+
+ if (ent.client.ps.gunframe == 9) {
+ // send muzzle flash
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_BFG | is_silenced);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ ent.client.ps.gunframe++;
+
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+ return true;
+ }
+
+ // cells can go down during windup (from power armor hits), so
+ // check again and abort firing if we don't have enough now
+ if (ent.client.pers.inventory[ent.client.ammo_index] < 50) {
+ ent.client.ps.gunframe++;
+ return true;
+ }
+
+ if (is_quad)
+ damage *= 4;
+
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+
+ Math3D.VectorScale(forward, -2, ent.client.kick_origin);
+
+ // make a big pitch kick with an inverse fall
+ ent.client.v_dmg_pitch= -40;
+ ent.client.v_dmg_roll= Lib.crandom() * 8;
+ ent.client.v_dmg_time= level.time + DAMAGE_TIME;
+
+ Math3D.VectorSet(offset, 8, 8, ent.viewheight - 8);
+ P_ProjectSource(ent.client, ent.s.origin, offset, forward, right, start);
+ Fire.fire_bfg(ent, start, forward, damage, 400, damage_radius);
+
+ ent.client.ps.gunframe++;
+
+ PlayerNoise(ent, start, PNOISE_WEAPON);
+
+ if (0 == ((int) dmflags.value & DF_INFINITE_AMMO))
+ ent.client.pers.inventory[ent.client.ammo_index] -= 50;
+
+ return true;
+ }
+ };
+
+ static int pause_frames[]= { 39, 45, 50, 55, 0 };
+ static int fire_frames[]= { 9, 17, 0 };
+
+ static EntThinkAdapter Weapon_BFG= new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+
+ Weapon_Generic(ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
+ return true;
+ }
+ };
+}
diff --git a/src/jake2/game/GameSVCmds.java b/src/jake2/game/GameSVCmds.java
new file mode 100644
index 0000000..dc0b4f9
--- /dev/null
+++ b/src/jake2/game/GameSVCmds.java
@@ -0,0 +1,306 @@
+/*
+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 01.02.2004 by RST.
+// $Id: GameSVCmds.java,v 1.1 2004-07-07 19:59:00 hzi Exp $
+
+package jake2.game;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.StringTokenizer;
+
+import com.sun.corba.se.internal.ior.ByteBuffer;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class GameSVCmds extends GameSpawn {
+
+ public static void Svcmd_Test_f() {
+ gi.cprintf(null, PRINT_HIGH, "Svcmd_Test_f()\n");
+ }
+
+ /*
+ ==============================================================================
+
+ PACKET FILTERING
+
+
+ You can add or remove addresses from the filter list with:
+
+ addip <ip>
+ removeip <ip>
+
+ The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40".
+
+ Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
+
+ listip
+ Prints the current list of filters.
+
+ writeip
+ Dumps "addip <ip>" commands to listip.cfg so it can be execed at a later date. The filter lists are not saved and restored by default, because I beleive it would cause too much confusion.
+
+ filterban <0 or 1>
+
+ If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
+
+ If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
+
+
+ ==============================================================================
+ */
+
+ public static class ipfilter_t {
+ int mask;
+ int compare;
+ };
+
+ public static final int MAX_IPFILTERS = 1024;
+
+ static ipfilter_t ipfilters[] = new ipfilter_t[MAX_IPFILTERS];
+ static {
+ for (int n = 0; n < MAX_IPFILTERS; n++)
+ ipfilters[n] = new ipfilter_t();
+ }
+
+ static int numipfilters;
+
+ /*
+ =================
+ StringToFilter
+ =================
+ */
+ static boolean StringToFilter(String s, ipfilter_t f) {
+ //char num[128];
+ String num;
+ int i, j;
+ byte b[] = { 0, 0, 0, 0 };
+ byte m[] = { 0, 0, 0, 0 };
+
+ try {
+ StringTokenizer tk = new StringTokenizer(s, ". ");
+
+ for (int n = 0; n < 4; n++) {
+ b[n] = (byte) atoi(tk.nextToken());
+ if (b[n] != 0)
+ m[n] = -1;
+ }
+
+ f.mask = java.nio.ByteBuffer.wrap(m).getInt();
+ f.compare = java.nio.ByteBuffer.wrap(b).getInt();
+ }
+ catch (Exception e) {
+ gi.cprintf(null, PRINT_HIGH, "Bad filter address: " + s + "\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ =================
+ SV_FilterPacket
+ =================
+ */
+ static boolean SV_FilterPacket(String from) {
+ int i;
+ int in;
+ int m[] = {0,0,0,0};
+
+ int p=0;
+ char c;
+
+ i = 0;
+
+ while (p < from.length() && i < 4) {
+ m[i] = 0;
+
+
+ c = from.charAt(p);
+ while(c >= '0' && c <= '9') {
+ m[i] = m[i] * 10 + (c - '0');
+ c = from.charAt(p++);
+ }
+ if (p == from.length() || c == ':')
+ break;
+
+ i++;
+ p++;
+ }
+
+ in =(m[0] & 0xff) | ((m[1] & 0xff) << 8) | ((m[2] & 0xff) << 16) | ((m[3] & 0xff) << 24);
+
+ for (i = 0; i < numipfilters; i++)
+ if ((in & ipfilters[i].mask) == ipfilters[i].compare)
+ return ((int) filterban.value)!=0;
+
+ return ((int) 1-filterban.value)!=0;
+ }
+
+ /*
+ =================
+ SV_AddIP_f
+ =================
+ */
+ static void SVCmd_AddIP_f() {
+ int i;
+
+ if (gi.argc() < 3) {
+ gi.cprintf(null, PRINT_HIGH, "Usage: addip <ip-mask>\n");
+ return;
+ }
+
+ for (i = 0; i < numipfilters; i++)
+ if (ipfilters[i].compare == 0xffffffff)
+ break; // free spot
+ if (i == numipfilters) {
+ if (numipfilters == MAX_IPFILTERS) {
+ gi.cprintf(null, PRINT_HIGH, "IP filter list is full\n");
+ return;
+ }
+ numipfilters++;
+ }
+
+ if (!StringToFilter(gi.argv(2), ipfilters[i]))
+ ipfilters[i].compare = 0xffffffff;
+ }
+
+ /*
+ =================
+ SV_RemoveIP_f
+ =================
+ */
+ static void SVCmd_RemoveIP_f() {
+ ipfilter_t f = new ipfilter_t();
+ int i, j;
+
+ if (gi.argc() < 3) {
+ gi.cprintf(null, PRINT_HIGH, "Usage: sv removeip <ip-mask>\n");
+ return;
+ }
+
+ if (!StringToFilter(gi.argv(2), f))
+ return;
+
+ for (i = 0; i < numipfilters; i++)
+ if (ipfilters[i].mask == f.mask && ipfilters[i].compare == f.compare) {
+ for (j = i + 1; j < numipfilters; j++)
+ ipfilters[j - 1] = ipfilters[j];
+ numipfilters--;
+ gi.cprintf(null, PRINT_HIGH, "Removed.\n");
+ return;
+ }
+ gi.cprintf(null, PRINT_HIGH, "Didn't find " + gi.argv(2) + ".\n");
+ }
+
+ /*
+ =================
+ SV_ListIP_f
+ =================
+ */
+ static void SVCmd_ListIP_f() {
+ int i;
+ byte b[];
+
+ gi.cprintf(null, PRINT_HIGH, "Filter list:\n");
+ for (i = 0; i < numipfilters; i++) {
+ b = getIntBytes(ipfilters[i].compare);
+ gi.cprintf(null, PRINT_HIGH, (b[0] & 0xff) + "." + (b[1] & 0xff) + "." + (b[2] & 0xff) + "." + (b[3] & 0xff));
+ }
+ }
+
+ /*
+ =================
+ SV_WriteIP_f
+ =================
+ */
+ static void SVCmd_WriteIP_f() {
+ RandomAccessFile f;
+ //char name[MAX_OSPATH];
+ String name;
+ byte b[];
+
+ int i;
+ cvar_t game;
+
+ game = gi.cvar("game", "", 0);
+
+ if (game.string == null)
+ name = GAMEVERSION + "/listip.cfg";
+ else
+ name = game.string + "/listip.cfg";
+
+ gi.cprintf(null, PRINT_HIGH, "Writing " + name + ".\n");
+
+ f = fopen(name, "rw");
+ if (f == null) {
+ gi.cprintf(null, PRINT_HIGH, "Couldn't open " + name + "\n");
+ return;
+ }
+
+ try {
+ f.writeChars("set filterban " + (int) filterban.value + "\n");
+
+ for (i = 0; i < numipfilters; i++) {
+ b = getIntBytes(ipfilters[i].compare);
+ f.writeChars("sv addip " + (b[0] & 0xff) + "." + (b[1] & 0xff) + "." + (b[2] & 0xff) + "." + (b[3] & 0xff) + "\n");
+ }
+
+ }
+ catch (IOException e) {
+ Com.Printf("IOError in SVCmd_WriteIP_f:" + e);
+ }
+
+ fclose(f);
+ }
+
+ /*
+ =================
+ ServerCommand
+
+ ServerCommand will be called when an "sv" command is issued.
+ The game can issue gi.argc() / gi.argv() commands to get the rest
+ of the parameters
+ =================
+ */
+ public static void ServerCommand() {
+ String cmd;
+
+ cmd = gi.argv(1);
+ if (Q_stricmp(cmd, "test") == 0)
+ Svcmd_Test_f();
+ else if (Q_stricmp(cmd, "addip") == 0)
+ SVCmd_AddIP_f();
+ else if (Q_stricmp(cmd, "removeip") == 0)
+ SVCmd_RemoveIP_f();
+ else if (Q_stricmp(cmd, "listip") == 0)
+ SVCmd_ListIP_f();
+ else if (Q_stricmp(cmd, "writeip") == 0)
+ SVCmd_WriteIP_f();
+ else
+ gi.cprintf(null, PRINT_HIGH, "Unknown server command \"" + cmd + "\"\n");
+ }
+
+}
diff --git a/src/jake2/game/GameSave.java b/src/jake2/game/GameSave.java
new file mode 100644
index 0000000..d399b8c
--- /dev/null
+++ b/src/jake2/game/GameSave.java
@@ -0,0 +1,733 @@
+/*
+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 29.12.2003 by RST.
+// $Id: GameSave.java,v 1.1 2004-07-07 19:59:01 hzi Exp $
+
+package jake2.game;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.*;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+import jake2.util.*;
+
+public class GameSave extends GameFunc {
+
+ public static field_t levelfields[] =
+ {
+ new field_t("changemap", F_LSTRING),
+ new field_t("sight_client", F_EDICT),
+ new field_t("sight_entity", F_EDICT),
+ new field_t("sound_entity", F_EDICT),
+ new field_t("sound2_entity", F_EDICT),
+ new field_t(null, F_INT)};
+
+ public static field_t clientfields[] =
+ {
+ new field_t("pers.weapon", F_ITEM),
+ new field_t("pers.lastweapon", F_ITEM),
+ new field_t("newweapon", F_ITEM),
+ new field_t(null, F_INT)};
+
+ public static void CreateEdicts() {
+ g_edicts = new edict_t[game.maxentities];
+ for (int i = 0; i < game.maxentities; i++)
+ g_edicts[i] = new edict_t(i);
+ }
+
+ public static void CreateClients() {
+ game.clients = new gclient_t[game.maxclients];
+ for (int i = 0; i < game.maxclients; i++)
+ game.clients[i] = new gclient_t(i);
+
+ }
+
+ /*
+ ============
+ InitGame
+
+ This will be called when the dll is first loaded, which
+ only happens when a new game is started or a save game
+ is loaded.
+ ============
+ */
+ public static void InitGame() {
+ gi.dprintf("==== InitGame ====\n");
+
+ gun_x = gi.cvar("gun_x", "0", 0);
+ gun_y = gi.cvar("gun_y", "0", 0);
+ gun_z = gi.cvar("gun_z", "0", 0);
+
+ //FIXME: sv_ prefix is wrong for these
+ sv_rollspeed = gi.cvar("sv_rollspeed", "200", 0);
+ sv_rollangle = gi.cvar("sv_rollangle", "2", 0);
+ sv_maxvelocity = gi.cvar("sv_maxvelocity", "2000", 0);
+ sv_gravity = gi.cvar("sv_gravity", "800", 0);
+
+ // noset vars
+ dedicated = gi.cvar("dedicated", "0", CVAR_NOSET);
+
+ // latched vars
+ sv_cheats = gi.cvar("cheats", "0", CVAR_SERVERINFO | CVAR_LATCH);
+ gi.cvar("gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_LATCH);
+ gi.cvar("gamedate", __DATE__, CVAR_SERVERINFO | CVAR_LATCH);
+
+ maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
+ maxspectators = gi.cvar("maxspectators", "4", CVAR_SERVERINFO);
+ deathmatch = gi.cvar("deathmatch", "0", CVAR_LATCH);
+ coop = gi.cvar("coop", "0", CVAR_LATCH);
+ skill = gi.cvar("skill", "0", CVAR_LATCH);
+ maxentities = gi.cvar("maxentities", "1024", CVAR_LATCH);
+
+ // change anytime vars
+ dmflags = gi.cvar("dmflags", "0", CVAR_SERVERINFO);
+ fraglimit = gi.cvar("fraglimit", "0", CVAR_SERVERINFO);
+ timelimit = gi.cvar("timelimit", "0", CVAR_SERVERINFO);
+ password = gi.cvar("password", "", CVAR_USERINFO);
+ spectator_password = gi.cvar("spectator_password", "", CVAR_USERINFO);
+ needpass = gi.cvar("needpass", "0", CVAR_SERVERINFO);
+ filterban = gi.cvar("filterban", "1", 0);
+
+ g_select_empty = gi.cvar("g_select_empty", "0", CVAR_ARCHIVE);
+
+ run_pitch = gi.cvar("run_pitch", "0.002", 0);
+ run_roll = gi.cvar("run_roll", "0.005", 0);
+ bob_up = gi.cvar("bob_up", "0.005", 0);
+ bob_pitch = gi.cvar("bob_pitch", "0.002", 0);
+ bob_roll = gi.cvar("bob_roll", "0.002", 0);
+
+ // flood control
+ flood_msgs = gi.cvar("flood_msgs", "4", 0);
+ flood_persecond = gi.cvar("flood_persecond", "4", 0);
+ flood_waitdelay = gi.cvar("flood_waitdelay", "10", 0);
+
+ // dm map list
+ sv_maplist = gi.cvar("sv_maplist", "", 0);
+
+ // items
+ InitItems();
+
+ //Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
+ game.helpmessage1 = "";
+
+ //Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
+ game.helpmessage2 = "";
+
+ // initialize all entities for this game
+ game.maxentities = (int) maxentities.value;
+
+ //g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
+ CreateEdicts();
+
+ globals.edicts = g_edicts;
+ globals.max_edicts = game.maxentities;
+
+ // initialize all clients for this game
+ game.maxclients = (int) maxclients.value;
+
+ //game.clients = gi.TagMalloc(game.maxclients * sizeof(game.clients[0]), TAG_GAME);
+ CreateClients();
+
+ globals.num_edicts = game.maxclients + 1;
+ }
+
+ ////=========================================================
+ //
+ //public static void WriteField1 (FILE *f, field_t field, byte base)
+ //{
+ // void *p;
+ // int len;
+ // int index;
+ //
+ // if (field.flags & FFL_SPAWNTEMP)
+ // return;
+ //
+ // p = (void *)(base + field.ofs);
+ // switch (field.type)
+ // {
+ // case F_INT:
+ // case F_FLOAT:
+ // case F_ANGLEHACK:
+ // case F_VECTOR:
+ // case F_IGNORE:
+ // break;
+ //
+ // case F_LSTRING:
+ // case F_GSTRING:
+ // if ( *(char **)p )
+ // len = strlen(*(char **)p) + 1;
+ // else
+ // len = 0;
+ // *(int *)p = len;
+ // break;
+ // case F_EDICT:
+ // if ( *(edict_t **)p == NULL)
+ // index = -1;
+ // else
+ // index = *(edict_t **)p - g_edicts;
+ // *(int *)p = index;
+ // break;
+ // case F_CLIENT:
+ // if ( *(gclient_t **)p == NULL)
+ // index = -1;
+ // else
+ // index = *(gclient_t **)p - game.clients;
+ // *(int *)p = index;
+ // break;
+ // case F_ITEM:
+ // if ( *(edict_t **)p == NULL)
+ // index = -1;
+ // else
+ // index = *(gitem_t **)p - itemlist;
+ // *(int *)p = index;
+ // break;
+ //
+ // //relative to code segment
+ // case F_FUNCTION:
+ // if (*(byte **)p == NULL)
+ // index = 0;
+ // else
+ // index = *(byte **)p - ((byte *)InitGame);
+ // *(int *)p = index;
+ // break;
+ //
+ // //relative to data segment
+ // case F_MMOVE:
+ // if (*(byte **)p == NULL)
+ // index = 0;
+ // else
+ // index = *(byte **)p - (byte *)&mmove_reloc;
+ // *(int *)p = index;
+ // break;
+ //
+ // default:
+ // gi.error ("WriteEdict: unknown field type");
+ // }
+ //}
+ //
+ //
+ //void WriteField2 (FILE *f, field_t *field, byte *base)
+ //{
+ // int len;
+ // void *p;
+ //
+ // if (field.flags & FFL_SPAWNTEMP)
+ // return;
+ //
+ // p = (void *)(base + field.ofs);
+ // switch (field.type)
+ // {
+ // case F_LSTRING:
+ // if ( *(char **)p )
+ // {
+ // len = strlen(*(char **)p) + 1;
+ // fwrite (*(char **)p, len, 1, f);
+ // }
+ // break;
+ // }
+ //}
+ //
+ //void ReadField (FILE *f, field_t *field, byte *base)
+ //{
+ // void *p;
+ // int len;
+ // int index;
+ //
+ // if (field.flags & FFL_SPAWNTEMP)
+ // return;
+ //
+ // p = (void *)(base + field.ofs);
+ // switch (field.type)
+ // {
+ // case F_INT:
+ // case F_FLOAT:
+ // case F_ANGLEHACK:
+ // case F_VECTOR:
+ // case F_IGNORE:
+ // break;
+ //
+ // case F_LSTRING:
+ // len = *(int *)p;
+ // if (!len)
+ // *(char **)p = NULL;
+ // else
+ // {
+ // *(char **)p = gi.TagMalloc (len, TAG_LEVEL);
+ // fread (*(char **)p, len, 1, f);
+ // }
+ // break;
+ // case F_EDICT:
+ // index = *(int *)p;
+ // if ( index == -1 )
+ // *(edict_t **)p = NULL;
+ // else
+ // *(edict_t **)p = &g_edicts[index];
+ // break;
+ // case F_CLIENT:
+ // index = *(int *)p;
+ // if ( index == -1 )
+ // *(gclient_t **)p = NULL;
+ // else
+ // *(gclient_t **)p = &game.clients[index];
+ // break;
+ // case F_ITEM:
+ // index = *(int *)p;
+ // if ( index == -1 )
+ // *(gitem_t **)p = NULL;
+ // else
+ // *(gitem_t **)p = &itemlist[index];
+ // break;
+ //
+ // //relative to code segment
+ // case F_FUNCTION:
+ // index = *(int *)p;
+ // if ( index == 0 )
+ // *(byte **)p = NULL;
+ // else
+ // *(byte **)p = ((byte *)InitGame) + index;
+ // break;
+ //
+ // //relative to data segment
+ // case F_MMOVE:
+ // index = *(int *)p;
+ // if (index == 0)
+ // *(byte **)p = NULL;
+ // else
+ // *(byte **)p = (byte *)&mmove_reloc + index;
+ // break;
+ //
+ // default:
+ // gi.error ("ReadEdict: unknown field type");
+ // }
+ //}
+ //
+ ////=========================================================
+ //
+ ///*
+ //==============
+ //WriteClient
+ //
+ //All pointer variables (except function pointers) must be handled specially.
+ //==============
+ //*/
+ //void WriteClient (FILE *f, gclient_t *client)
+ //{
+ // field_t *field;
+ // gclient_t temp;
+ //
+ // // all of the ints, floats, and vectors stay as they are
+ // temp = *client;
+ //
+ // // change the pointers to lengths or indexes
+ // for (field=clientfields ; field.name ; field++)
+ // {
+ // WriteField1 (f, field, (byte *)&temp);
+ // }
+ //
+ // // write the block
+ // fwrite (&temp, sizeof(temp), 1, f);
+ //
+ // // now write any allocated data following the edict
+ // for (field=clientfields ; field.name ; field++)
+ // {
+ // WriteField2 (f, field, (byte *)client);
+ // }
+ //}
+ //
+ /*
+ ==============
+ ReadClient
+
+ All pointer variables (except function pointers) must be handled specially.
+ ==============
+ */
+
+ //} //
+
+ /*
+ //============
+ //WriteGame
+ //
+ //This will be called whenever the game goes to a new level,
+ //and when the user explicitly saves the game.
+ //
+ //Game information include cross level data, like multi level
+ //triggers, help computer info, and all client states.
+ //
+ //A single player death will automatically restore from the
+ //last save position.
+ //============
+ //*/
+ //public static void WriteGame (String filename, boolean autosave)
+ //{
+ // FILE *f;
+ // int i;
+ // char str[16];
+ //
+ // if (!autosave)
+ // SaveClientData ();
+ //
+ // f = fopen (filename, "rw");
+ // if (!f)
+ // gi.error ("Couldn't open %s", filename);
+ //
+ // memset (str, 0, sizeof(str));
+ // strcpy (str, __DATE__);
+ // fwrite (str, sizeof(str), 1, f);
+ //
+ // game.autosaved = autosave;
+ // fwrite (&game, sizeof(game), 1, f);
+ // game.autosaved = false;
+ //
+ // for (i=0 ; i<game.maxclients ; i++)
+ // WriteClient (f, &game.clients[i]);
+ //
+ // fclose (f);
+ //}
+ //
+
+ public static void ReadGame(String filename) {
+
+ RandomAccessFile f = null;
+
+ try {
+
+ f = new RandomAccessFile(filename, "r");
+
+ byte buf[] = new byte[(int) f.length()];
+
+ Com.Printf("loading game:" + filename);
+
+ f.readFully(buf);
+
+ ByteBuffer bb = ByteBuffer.wrap(buf);
+
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ CreateEdicts();
+
+ game.load(bb);
+ //game.dump();
+
+ for (int i = 0; i < game.maxclients; i++) {
+ game.clients[i] = new gclient_t(i);
+ game.clients[i].load(bb);
+ }
+
+ Com.Println("");
+ Com.Println("file length:" + f.length());
+ Com.Println("processed bytes:" + bb.position());
+
+ }
+
+ catch (Exception e) {
+ e.printStackTrace();
+ //gi.error ("File problems in "+ filename);
+ } //if (!f)
+ // gi.error ("Couldn't open %s", filename);
+ //
+ // fread (str, sizeof(str), 1, f);
+ // if (strcmp (str, __DATE__))
+ // {
+ // fclose (f);
+ // gi.error ("Savegame from an older version.\n");
+ // }
+ //
+ // CreateEdicts();
+ //
+ // fread (game, sizeof(game), 1, f);
+ //
+ // CreateClients();
+ //
+ // for (i=0 ; i<game.maxclients ; i++)
+ // ReadClient (f, game.clients[i]);
+ //
+ // fclose (f);
+ try {
+ f.close();
+ }
+ catch (IOException e) {
+ Com.Error(Defines.ERR_DROP, "Unable to load savegame");
+ }
+ }
+
+ //
+ ////==========================================================
+ //
+ //
+ ///*
+ //==============
+ //WriteEdict
+ //
+ //All pointer variables (except function pointers) must be handled specially.
+ //==============
+ //*/
+ //void WriteEdict (FILE *f, edict_t *ent)
+ //{
+ // field_t *field;
+ // edict_t temp;
+ //
+ // // all of the ints, floats, and vectors stay as they are
+ // temp = *ent;
+ //
+ // // change the pointers to lengths or indexes
+ // for (field=fields ; field.name ; field++)
+ // {
+ // WriteField1 (f, field, (byte *)&temp);
+ // }
+ //
+ // // write the block
+ // fwrite (&temp, sizeof(temp), 1, f);
+ //
+ // // now write any allocated data following the edict
+ // for (field=fields ; field.name ; field++)
+ // {
+ // WriteField2 (f, field, (byte *)ent);
+ // }
+ //
+ //}
+ //
+ ///*
+ //==============
+ //WriteLevelLocals
+ //
+ //All pointer variables (except function pointers) must be handled specially.
+ //==============
+ //*/
+ //void WriteLevelLocals (FILE *f)
+ //{
+ // field_t *field;
+ // level_locals_t temp;
+ //
+ // // all of the ints, floats, and vectors stay as they are
+ // temp = level;
+ //
+ // // change the pointers to lengths or indexes
+ // for (field=levelfields ; field.name ; field++)
+ // {
+ // WriteField1 (f, field, (byte *)&temp);
+ // }
+ //
+ // // write the block
+ // fwrite (&temp, sizeof(temp), 1, f);
+ //
+ // // now write any allocated data following the edict
+ // for (field=levelfields ; field.name ; field++)
+ // {
+ // WriteField2 (f, field, (byte *)&level);
+ // }
+ //}
+ //
+ //
+ ///*
+ //==============
+ //ReadEdict
+ //
+ //All pointer variables (except function pointers) must be handled specially.
+ //==============
+ //*/
+ //void ReadEdict (FILE *f, edict_t *ent)
+ //{
+ // field_t *field;
+ //
+ // fread (ent, sizeof(*ent), 1, f);
+ //
+ // for (field=fields ; field.name ; field++)
+ // {
+ // ReadField (f, field, (byte *)ent);
+ // }
+ //}
+ //
+ ///*
+ //==============
+ //ReadLevelLocals
+ //
+ //All pointer variables (except function pointers) must be handled specially.
+ //==============
+ //*/
+ //void ReadLevelLocals (FILE *f)
+ //{
+ // field_t *field;
+ //
+ // fread (&level, sizeof(level), 1, f);
+ //
+ // for (field=levelfields ; field.name ; field++)
+ // {
+ // ReadField (f, field, (byte *)&level);
+ // }
+ //}
+ //
+ ///*
+ //=================
+ //WriteLevel
+ //
+ //=================
+ //*/
+ //void WriteLevel (char *filename)
+ //{
+ // int i;
+ // edict_t *ent;
+ // FILE *f;
+ // void *base;
+ //
+ // f = fopen (filename, "rw");
+ // if (!f)
+ // gi.error ("Couldn't open %s", filename);
+ //
+ // // write out edict size for checking
+ // i = sizeof(edict_t);
+ // fwrite (&i, sizeof(i), 1, f);
+ //
+ // // write out a function pointer for checking
+ // base = (void *)InitGame;
+ // fwrite (&base, sizeof(base), 1, f);
+ //
+ // // write out level_locals_t
+ // WriteLevelLocals (f);
+ //
+ // // write out all the entities
+ // for (i=0 ; i<globals.num_edicts ; i++)
+ // {
+ // ent = &g_edicts[i];
+ // if (!ent.inuse)
+ // continue;
+ // fwrite (&i, sizeof(i), 1, f);
+ // WriteEdict (f, ent);
+ // }
+ // i = -1;
+ // fwrite (&i, sizeof(i), 1, f);
+ //
+ // fclose (f);
+ //}
+ //
+ //
+ ///*
+ //=================
+ //ReadLevel
+ //
+ //SpawnEntities will allready have been called on the
+ //level the same way it was when the level was saved.
+ //
+ //That is necessary to get the baselines
+ //set up identically.
+ //
+ //The server will have cleared all of the world links before
+ //calling ReadLevel.
+ //
+ //No clients are connected yet.
+ //=================
+ //*/
+ //void ReadLevel (char *filename)
+ //{
+ // int entnum;
+ // FILE *f;
+ // int i;
+ // void *base;
+ // edict_t *ent;
+ //
+ // f = fopen (filename, "r");
+ // if (!f)
+ // gi.error ("Couldn't open %s", filename);
+ //
+ // // free any dynamic memory allocated by loading the level
+ // // base state
+ // gi.FreeTags (TAG_LEVEL);
+ //
+ // // wipe all the entities
+ // memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
+ // globals.num_edicts = maxclients.value+1;
+ //
+ // // check edict size
+ // fread (&i, sizeof(i), 1, f);
+ // if (i != sizeof(edict_t))
+ // {
+ // fclose (f);
+ // gi.error ("ReadLevel: mismatched edict size");
+ // }
+ //
+ // // check function pointer base address
+ // fread (&base, sizeof(base), 1, f);
+ //#ifdef _WIN32
+ // if (base != (void *)InitGame)
+ // {
+ // fclose (f);
+ // gi.error ("ReadLevel: function pointers have moved");
+ // }
+ //#else
+ // gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
+ //#endif
+ //
+ // // load the level locals
+ // ReadLevelLocals (f);
+ //
+ // // load all the entities
+ // while (1)
+ // {
+ // if (fread (&entnum, sizeof(entnum), 1, f) != 1)
+ // {
+ // fclose (f);
+ // gi.error ("ReadLevel: failed to read entnum");
+ // }
+ // if (entnum == -1)
+ // break;
+ // if (entnum >= globals.num_edicts)
+ // globals.num_edicts = entnum+1;
+ //
+ // ent = &g_edicts[entnum];
+ // ReadEdict (f, ent);
+ //
+ // // let the server rebuild world links for this ent
+ // memset (&ent.area, 0, sizeof(ent.area));
+ // gi.linkentity (ent);
+ // }
+ //
+ // fclose (f);
+ //
+ // // mark all clients as unconnected
+ // for (i=0 ; i<maxclients.value ; i++)
+ // {
+ // ent = &g_edicts[i+1];
+ // ent.client = game.clients + i;
+ // ent.client.pers.connected = false;
+ // }
+ //
+ // // do any load time things at this point
+ // for (i=0 ; i<globals.num_edicts ; i++)
+ // {
+ // ent = &g_edicts[i];
+ //
+ // if (!ent.inuse)
+ // continue;
+ //
+ // // fire any cross-level triggers
+ // if (ent.classname)
+ // if (strcmp(ent.classname, "target_crosslevel_target") == 0)
+ // ent.nextthink = level.time + ent.delay;
+ // }
+ //}
+
+}
diff --git a/src/jake2/game/GameSpawn.java b/src/jake2/game/GameSpawn.java
new file mode 100644
index 0000000..2966f06
--- /dev/null
+++ b/src/jake2/game/GameSpawn.java
@@ -0,0 +1,803 @@
+/*
+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 18.11.2003 by RST.
+// $Id: GameSpawn.java,v 1.1 2004-07-07 19:59:02 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.qcommon.*;
+import jake2.game.*;
+
+public class GameSpawn extends GameSave {
+
+ static EntThinkAdapter SP_item_health = new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_item_health(ent);return true;}};
+
+ static EntThinkAdapter SP_item_health_small = new EntThinkAdapter() {public boolean think(edict_t ent){ Game.SP_item_health_small(ent);return true;}};
+ static EntThinkAdapter SP_item_health_large = new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_item_health_large(ent); return true;}};
+ static EntThinkAdapter SP_item_health_mega = new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_item_health_mega(ent); return true;}};
+
+ static EntThinkAdapter SP_info_player_start = new EntThinkAdapter() {public boolean think(edict_t ent){ SP_info_player_start(ent);return true;}};
+ static EntThinkAdapter SP_info_player_deathmatch = new EntThinkAdapter() {public boolean think(edict_t ent){ SP_info_player_deathmatch(ent);return true;}};
+ static EntThinkAdapter SP_info_player_coop = new EntThinkAdapter() {public boolean think(edict_t ent){SP_info_player_coop(ent); return true;}};
+ static EntThinkAdapter SP_info_player_intermission = new EntThinkAdapter() {public boolean think(edict_t ent){SP_info_player_intermission(); return true;}};
+
+ static EntThinkAdapter SP_func_plat = new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_func_plat(ent); return true;}};
+ //static EntThinkAdapter SP_func_rotating = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_button = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_door = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_door_secret = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_door_rotating = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+ static EntThinkAdapter SP_func_water = new EntThinkAdapter() {public boolean think(edict_t ent){SP_func_water(ent); return true;}};
+ static EntThinkAdapter SP_func_train = new EntThinkAdapter() {public boolean think(edict_t ent){SP_func_train(ent); return true;}};
+// static EntThinkAdapter SP_func_conveyor = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_wall = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_object = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_explosive = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_timer = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_func_areaportal = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+ static EntThinkAdapter SP_func_clock = new EntThinkAdapter() {public boolean think(edict_t ent){SP_func_clock(ent); return true;}};
+// static EntThinkAdapter SP_func_killbox = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// static EntThinkAdapter SP_trigger_always = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_once = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_multiple = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_relay = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_push = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_hurt = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_key = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_counter = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_elevator = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_gravity = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_trigger_monsterjump = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// static EntThinkAdapter SP_target_temp_entity = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_speaker = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_explosion = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_changelevel = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_secret = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_goal = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_splash = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_spawner = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_blaster = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_crosslevel_trigger = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_crosslevel_target = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_laser = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_help = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_actor = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_lightramp = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_earthquake = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_character = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_target_string = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// //static EntThinkAdapter SP_worldspawn = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_viewthing = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// static EntThinkAdapter SP_light = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_light_mine1 = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_light_mine2 = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_info_null = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_info_notnull = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_path_corner = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_point_combat = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// static EntThinkAdapter SP_misc_explobox = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_banner = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_satellite_dish = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_actor = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_gib_arm = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_gib_leg = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_gib_head = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_insane = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_deadsoldier = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_viper = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_viper_bomb = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_bigviper = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_strogg_ship = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_teleporter = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_teleporter_dest = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_blackhole = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_eastertank = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_easterchick = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_misc_easterchick2 = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// static EntThinkAdapter SP_monster_berserk = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_gladiator = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_gunner = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_infantry = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_soldier_light = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_soldier = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_soldier_ss = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_tank = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_medic = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_flipper = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_chick = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_parasite = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_flyer = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_brain = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_floater = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_hover = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_mutant = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_supertank = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_boss2 = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_jorg = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_monster_boss3_stand = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// static EntThinkAdapter SP_monster_commander_body = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+//
+// static EntThinkAdapter SP_turret_breach = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_turret_base = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+// static EntThinkAdapter SP_turret_driver = new EntThinkAdapter() {public boolean think(edict_t ent){ return true;}};
+
+ /*
+ =============
+ ED_NewString
+ =============
+ */
+ static String ED_NewString(String string) {
+
+ //String newb, new_p;
+ int i, l;
+
+ l = Lib.strlen(string) + 1;
+ //newb = gi.TagMalloc(l, TAG_LEVEL);
+
+ StringBuffer newb = new StringBuffer(l);
+
+ for (i = 0; i < l - 1; i++) {
+ char c;
+
+ c = string.charAt(i);
+ if (c == '\\' && i < l - 1) {
+ c = string.charAt(i++);
+ if (c == 'n')
+ newb.append('\n');
+ else
+ newb.append('\\');
+ }
+ else
+ newb.append(c);
+ }
+
+ return newb.toString();
+ }
+
+ /*
+ ===============
+ ED_ParseField
+
+ Takes a key/value pair and sets the binary values
+ in an edict
+ ===============
+ */
+ static void ED_ParseField(String key, String value, edict_t ent) {
+ field_t f1;
+ byte b;
+ float v;
+ float[] vec = { 0, 0, 0 };
+
+ if (!st.set(key, value))
+ if (!ent.set(key, value))
+ gi.dprintf("??? The key [" + key + "] is not a field\n");
+
+
+
+ /** OLD CODE, delegated to ent.set(...) and st.set(...)
+
+ for (f = fields; f.name; f++) {
+ if (!(f.flags & FFL_NOSPAWN) && !Q_stricmp(f.name, key)) {
+ // found it
+ if (f.flags & FFL_SPAWNTEMP)
+ b = (byte *) & st;
+ else
+ b = (byte *) ent;
+
+ switch (f.type) {
+ case F_LSTRING :
+ * (String *) (b + f.ofs) = ED_NewString(value);
+ break;
+ case F_VECTOR :
+ sscanf(value, "%f %f %f", & vec[0], & vec[1], & vec[2]);
+ ((float *) (b + f.ofs))[0] = vec[0];
+ ((float *) (b + f.ofs))[1] = vec[1];
+ ((float *) (b + f.ofs))[2] = vec[2];
+ break;
+ case F_INT :
+ * (int *) (b + f.ofs) = atoi(value);
+ break;
+ case F_FLOAT :
+ * (float *) (b + f.ofs) = atof(value);
+ break;
+ case F_ANGLEHACK :
+ v = atof(value);
+ ((float *) (b + f.ofs))[0] = 0;
+ ((float *) (b + f.ofs))[1] = v;
+ ((float *) (b + f.ofs))[2] = 0;
+ break;
+ case F_IGNORE :
+ break;
+ }
+ return;
+ }
+ }
+ gi.dprintf("%s is not a field\n", key);
+
+ */
+ }
+
+ /*
+ ====================
+ ED_ParseEdict
+
+ Parses an edict out of the given string, returning the new position
+ ed should be a properly initialized empty edict.
+ ====================
+ */
+
+ static void ED_ParseEdict(Com.ParseHelp ph, edict_t ent) {
+
+ boolean init;
+ String keyname;
+ String com_token;
+ init = false;
+
+ while (true) {
+
+ // parse key
+ com_token = Com.Parse(ph);
+ if (com_token.equals("}"))
+ break;
+
+ if (ph.isEof())
+ gi.error("ED_ParseEntity: EOF without closing brace");
+
+ keyname = com_token;
+
+ // parse value
+ com_token = Com.Parse(ph);
+
+ if (ph.isEof())
+ gi.error("ED_ParseEntity: EOF without closing brace");
+
+ if (com_token.equals("}"))
+ gi.error("ED_ParseEntity: closing brace without data");
+
+ init = true;
+ // keynames with a leading underscore are used for utility comments,
+ // and are immediately discarded by quake
+ if (keyname.charAt(0) == '_')
+ continue;
+
+ ED_ParseField(keyname, com_token, ent);
+
+ }
+
+ if (!init)
+ ent.clear();
+
+ return;
+ }
+
+ /*
+ ================
+ G_FindTeams
+
+ Chain together all entities with a matching team field.
+
+ All but the first will have the FL_TEAMSLAVE flag set.
+ All but the last will have the teamchain field set to the next one
+ ================
+ */
+
+ static void G_FindTeams() {
+ edict_t e, e2, chain;
+ int i, j;
+ int c, c2;
+ c = 0;
+ c2 = 0;
+ for (i = 1; i < globals.num_edicts; i++) {
+ e = g_edicts[i];
+
+ if (!e.inuse)
+ continue;
+ if (e.team == null)
+ continue;
+ if ((e.flags & FL_TEAMSLAVE) != 0)
+ continue;
+ chain = e;
+ e.teammaster = e;
+ c++;
+ c2++;
+ Com.Printf("Team:" + e.team+" entity: " + e.index + "\n");
+ for (j = i + 1; j < globals.num_edicts; j++) {
+ e2 = g_edicts[j];
+ if (!e2.inuse)
+ continue;
+ if (null == e2.team)
+ continue;
+ if ((e2.flags & FL_TEAMSLAVE) != 0)
+ continue;
+ if (0 == Lib.strcmp(e.team, e2.team)) {
+ c2++;
+ chain.teamchain = e2;
+ e2.teammaster = e;
+ chain = e2;
+ e2.flags |= FL_TEAMSLAVE;
+
+ }
+ }
+ }
+
+ gi.dprintf("" + c + " teams with " + c2 + " entities\n");
+ }
+
+ /*
+ ==============
+ SpawnEntities
+
+ Creates a server's entity / program execution context by
+ parsing textual entity definitions out of an ent file.
+ ==============
+ */
+
+ static void SpawnEntities(String mapname, String entities, String spawnpoint) {
+ edict_t ent;
+ int inhibit;
+ String com_token;
+ int i;
+ float skill_level;
+ //skill.value =2.0f;
+ skill_level = (float) Math.floor(skill.value);
+
+ if (skill_level < 0)
+ skill_level = 0;
+ if (skill_level > 3)
+ skill_level = 3;
+ if (skill.value != skill_level)
+ gi.cvar_forceset("skill", "" + skill_level);
+
+ PlayerClient.SaveClientData();
+
+ //level.clear();
+ Com.Printf("game.maxentities=" + game.maxentities + "\n");
+ level = new level_locals_t();
+ for (int n=0; n < game.maxentities; n++)
+ {
+ g_edicts[n] = new edict_t(n);
+ }
+ //memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0]));
+ level.mapname = mapname;
+ game.spawnpoint = spawnpoint;
+ // set client fields on player ents
+ for (i = 0; i < game.maxclients; i++)
+ g_edicts[i + 1].client = game.clients[i];
+
+ ent = null;
+ inhibit = 0; // parse ents
+ //Com.Printf("========================\n");
+ //Com.Printf("entities(" + entities.length() + ") = \n" + entities + "\n");
+ //Com.Printf("========================\n");
+
+ Com.ParseHelp ph = new Com.ParseHelp(entities);
+
+ //Com.DPrintf("* * * die scheiss edict- nummer stimmen nicht ??? * * * \n");
+ while (true) { // parse the opening brace
+
+ com_token = Com.Parse(ph);
+ if (ph.isEof())
+ break;
+ if (!com_token.startsWith("{"))
+ gi.error("ED_LoadFromFile: found "+com_token+" when expecting {");
+
+ if (ent==null)
+ ent = g_edicts[0];
+ else
+ ent = G_Spawn();
+
+ Com.DPrintf("===\n");
+
+ Com.DPrintf("allocated new edict:" + ent.index + "\n");
+ ED_ParseEdict(ph, ent);
+ Com.DPrintf("ent.classname:" + ent.classname + "\n");
+ Com.DPrintf("ent.spawnflags:" + Integer.toHexString(ent.spawnflags) + "\n");
+ // yet another map hack
+ if (0==Q_stricmp(level.mapname, "command") && 0==Q_stricmp(ent.classname, "trigger_once") &&
+ 0==Q_stricmp(ent.model, "*27"))
+ ent.spawnflags &= ~SPAWNFLAG_NOT_HARD;
+
+ // remove things (except the world) from different skill levels or deathmatch
+ if (ent != g_edicts[0]) {
+ if (deathmatch.value!=0) {
+ if ((ent.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)!=0) {
+ G_FreeEdict(ent);
+ inhibit++;
+ continue;
+ }
+ }
+ else {
+ if (/* ((coop.value) && (ent.spawnflags & SPAWNFLAG_NOT_COOP)) || */
+ ((skill.value == 0) && (ent.spawnflags & SPAWNFLAG_NOT_EASY)!=0)
+ || ((skill.value == 1) && (ent.spawnflags & SPAWNFLAG_NOT_MEDIUM)!=0)
+ || (((skill.value == 2) || (skill.value == 3)) && (ent.spawnflags & SPAWNFLAG_NOT_HARD)!=0)) {
+ G_FreeEdict(ent);
+ inhibit++;
+ continue;
+ }
+ }
+
+ ent.spawnflags
+ &= ~(SPAWNFLAG_NOT_EASY | SPAWNFLAG_NOT_MEDIUM | SPAWNFLAG_NOT_HARD | SPAWNFLAG_NOT_COOP | SPAWNFLAG_NOT_DEATHMATCH);
+ }
+
+ ED_CallSpawn(ent);
+ }
+ gi.dprintf("player skill level:" +skill.value + "\n");
+ gi.dprintf(inhibit + " entities inhibited\n");
+ i = 1;
+ G_FindTeams();
+ PlayerTrail.Init();
+ }
+
+ static String single_statusbar = "yb -24 " // health
+ +"xv 0 " + "hnum " + "xv 50 " + "pic 0 " // ammo
+ +"if 2 " + " xv 100 " + " anum " + " xv 150 " + " pic 2 " + "endif " // armor
+ +"if 4 " + " xv 200 " + " rnum " + " xv 250 " + " pic 4 " + "endif " // selected item
+ +"if 6 " + " xv 296 " + " pic 6 " + "endif " + "yb -50 " // picked up item
+ +"if 7 " + " xv 0 " + " pic 7 " + " xv 26 " + " yb -42 " + " stat_string 8 " + " yb -50 " + "endif "
+ // timer
+ +"if 9 " + " xv 262 " + " num 2 10 " + " xv 296 " + " pic 9 " + "endif "
+ // help / weapon icon
+ +"if 11 " + " xv 148 " + " pic 11 " + "endif ";
+
+ static String dm_statusbar = "yb -24 " // health
+ +"xv 0 " + "hnum " + "xv 50 " + "pic 0 " // ammo
+ +"if 2 " + " xv 100 " + " anum " + " xv 150 " + " pic 2 " + "endif " // armor
+ +"if 4 " + " xv 200 " + " rnum " + " xv 250 " + " pic 4 " + "endif " // selected item
+ +"if 6 " + " xv 296 " + " pic 6 " + "endif " + "yb -50 " // picked up item
+ +"if 7 " + " xv 0 " + " pic 7 " + " xv 26 " + " yb -42 " + " stat_string 8 " + " yb -50 " + "endif "
+ // timer
+ +"if 9 " + " xv 246 " + " num 2 10 " + " xv 296 " + " pic 9 " + "endif "
+ // help / weapon icon
+ +"if 11 " + " xv 148 " + " pic 11 " + "endif " // frags
+ +"xr -50 " + "yt 2 " + "num 3 14 " // spectator
+ +"if 17 " + "xv 0 " + "yb -58 " + "string2 \"SPECTATOR MODE\" " + "endif " // chase camera
+ +"if 16 " + "xv 0 " + "yb -68 " + "string \"Chasing\" " + "xv 64 " + "stat_string 16 " + "endif ";
+
+
+ /*QUAKED worldspawn (0 0 0) ?
+
+ Only used for the world.
+ "sky" environment map name
+ "skyaxis" vector axis for rotating sky
+ "skyrotate" speed of rotation in degrees/second
+ "sounds" music cd track number
+ "gravity" 800 is default gravity
+ "message" text to print at user logon
+ */
+
+ static EntThinkAdapter SP_worldspawn = new EntThinkAdapter() {
+
+ public boolean think(edict_t ent) {
+ ent.movetype = MOVETYPE_PUSH;
+ ent.solid = SOLID_BSP;
+ ent.inuse = true;
+ // since the world doesn't use G_Spawn()
+ ent.s.modelindex = 1;
+ // world model is always index 1
+ //---------------
+ // reserve some spots for dead player bodies for coop / deathmatch
+ InitBodyQue();
+ // set configstrings for items
+ SetItemNames();
+ if (st.nextmap != null)
+ level.nextmap = st.nextmap;
+ // make some data visible to the server
+ if (ent.message != null && ent.message.length() > 0) {
+ gi.configstring(CS_NAME, ent.message);
+ level.level_name = ent.message;
+ }
+ else
+ level.level_name = level.mapname;
+ if (st.sky != null && st.sky.length() > 0)
+ gi.configstring(CS_SKY, st.sky);
+ else
+ gi.configstring(CS_SKY, "unit1_");
+ gi.configstring(CS_SKYROTATE, "" + st.skyrotate);
+ gi.configstring(CS_SKYAXIS, Lib.vtos(st.skyaxis));
+ gi.configstring(CS_CDTRACK, "" + ent.sounds);
+ gi.configstring(CS_MAXCLIENTS, "" + (int) (maxclients.value));
+ // status bar program
+ if (deathmatch.value != 0)
+ gi.configstring(CS_STATUSBAR, "" + dm_statusbar);
+ else
+ gi.configstring(CS_STATUSBAR, "" + single_statusbar);
+ //---------------
+ // help icon for statusbar
+ gi.imageindex("i_help");
+ level.pic_health = gi.imageindex("i_health");
+ gi.imageindex("help");
+ gi.imageindex("field_3");
+ if (st.gravity != null)
+ gi.cvar_set("sv_gravity", "800");
+ else
+ gi.cvar_set("sv_gravity", st.gravity);
+ snd_fry = gi.soundindex("player/fry.wav");
+ // standing in lava / slime
+ PrecacheItem(FindItem("Blaster"));
+ gi.soundindex("player/lava1.wav");
+ gi.soundindex("player/lava2.wav");
+ gi.soundindex("misc/pc_up.wav");
+ gi.soundindex("misc/talk1.wav");
+ gi.soundindex("misc/udeath.wav");
+ // gibs
+ gi.soundindex("items/respawn1.wav");
+ // sexed sounds
+ gi.soundindex("*death1.wav");
+ gi.soundindex("*death2.wav");
+ gi.soundindex("*death3.wav");
+ gi.soundindex("*death4.wav");
+ gi.soundindex("*fall1.wav");
+ gi.soundindex("*fall2.wav");
+ gi.soundindex("*gurp1.wav");
+ // drowning damage
+ gi.soundindex("*gurp2.wav");
+ gi.soundindex("*jump1.wav");
+ // player jump
+ gi.soundindex("*pain25_1.wav");
+ gi.soundindex("*pain25_2.wav");
+ gi.soundindex("*pain50_1.wav");
+ gi.soundindex("*pain50_2.wav");
+ gi.soundindex("*pain75_1.wav");
+ gi.soundindex("*pain75_2.wav");
+ gi.soundindex("*pain100_1.wav");
+ gi.soundindex("*pain100_2.wav");
+ // sexed models
+ // THIS ORDER MUST MATCH THE DEFINES IN g_local.h
+ // you can add more, max 15
+ gi.modelindex("#w_blaster.md2");
+ gi.modelindex("#w_shotgun.md2");
+ gi.modelindex("#w_sshotgun.md2");
+ gi.modelindex("#w_machinegun.md2");
+ gi.modelindex("#w_chaingun.md2");
+ gi.modelindex("#a_grenades.md2");
+ gi.modelindex("#w_glauncher.md2");
+ gi.modelindex("#w_rlauncher.md2");
+ gi.modelindex("#w_hyperblaster.md2");
+ gi.modelindex("#w_railgun.md2");
+ gi.modelindex("#w_bfg.md2");
+ //-------------------
+ gi.soundindex("player/gasp1.wav");
+ // gasping for air
+ gi.soundindex("player/gasp2.wav");
+ // head breaking surface, not gasping
+ gi.soundindex("player/watr_in.wav");
+ // feet hitting water
+ gi.soundindex("player/watr_out.wav");
+ // feet leaving water
+ gi.soundindex("player/watr_un.wav");
+ // head going underwater
+ gi.soundindex("player/u_breath1.wav");
+ gi.soundindex("player/u_breath2.wav");
+ gi.soundindex("items/pkup.wav");
+ // bonus item pickup
+ gi.soundindex("world/land.wav");
+ // landing thud
+ gi.soundindex("misc/h2ohit1.wav");
+ // landing splash
+ gi.soundindex("items/damage.wav");
+ gi.soundindex("items/protect.wav");
+ gi.soundindex("items/protect4.wav");
+ gi.soundindex("weapons/noammo.wav");
+ gi.soundindex("infantry/inflies1.wav");
+ sm_meat_index = gi.modelindex("models/objects/gibs/sm_meat/tris.md2");
+ gi.modelindex("models/objects/gibs/arm/tris.md2");
+ gi.modelindex("models/objects/gibs/bone/tris.md2");
+ gi.modelindex("models/objects/gibs/bone2/tris.md2");
+ gi.modelindex("models/objects/gibs/chest/tris.md2");
+ gi.modelindex("models/objects/gibs/skull/tris.md2");
+ gi.modelindex("models/objects/gibs/head2/tris.md2");
+ //
+ // Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
+ //
+ // 0 normal
+ gi.configstring(CS_LIGHTS + 0, "m");
+ // 1 FLICKER (first variety)
+ gi.configstring(CS_LIGHTS + 1, "mmnmmommommnonmmonqnmmo");
+ // 2 SLOW STRONG PULSE
+ gi.configstring(CS_LIGHTS + 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
+ // 3 CANDLE (first variety)
+ gi.configstring(CS_LIGHTS + 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
+ // 4 FAST STROBE
+ gi.configstring(CS_LIGHTS + 4, "mamamamamama");
+ // 5 GENTLE PULSE 1
+ gi.configstring(CS_LIGHTS + 5, "jklmnopqrstuvwxyzyxwvutsrqponmlkj");
+ // 6 FLICKER (second variety)
+ gi.configstring(CS_LIGHTS + 6, "nmonqnmomnmomomno");
+ // 7 CANDLE (second variety)
+ gi.configstring(CS_LIGHTS + 7, "mmmaaaabcdefgmmmmaaaammmaamm");
+ // 8 CANDLE (third variety)
+ gi.configstring(CS_LIGHTS + 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
+ // 9 SLOW STROBE (fourth variety)
+ gi.configstring(CS_LIGHTS + 9, "aaaaaaaazzzzzzzz");
+ // 10 FLUORESCENT FLICKER
+ gi.configstring(CS_LIGHTS + 10, "mmamammmmammamamaaamammma");
+ // 11 SLOW PULSE NOT FADE TO BLACK
+ gi.configstring(CS_LIGHTS + 11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
+ // styles 32-62 are assigned by the light program for switchable lights
+ // 63 testing
+ gi.configstring(CS_LIGHTS + 63, "a");
+ return true;
+ }
+ };
+ static spawn_t spawns[] =
+ {
+ new spawn_t("item_health", SP_item_health),
+ new spawn_t("item_health_small", SP_item_health_small),
+ new spawn_t("item_health_large", SP_item_health_large),
+ new spawn_t("item_health_mega", SP_item_health_mega),
+ new spawn_t("info_player_start", SP_info_player_start),
+ new spawn_t("info_player_deathmatch", SP_info_player_deathmatch),
+ new spawn_t("info_player_coop", SP_info_player_coop),
+ new spawn_t("info_player_intermission", SP_info_player_intermission),
+ new spawn_t("func_plat", SP_func_plat),
+ new spawn_t("func_button", SP_func_button),
+ new spawn_t("func_door", SP_func_door),
+ new spawn_t("func_door_secret", SP_func_door_secret),
+ new spawn_t("func_door_rotating", SP_func_door_rotating),
+ new spawn_t("func_rotating", SP_func_rotating),
+ new spawn_t("func_train", SP_func_train),
+ new spawn_t("func_water", SP_func_water),
+ new spawn_t("func_conveyor", SP_func_conveyor),
+ new spawn_t("func_areaportal", SP_func_areaportal),
+ new spawn_t("func_clock", SP_func_clock),
+ new spawn_t("func_wall", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_func_wall(ent);return true;}}),
+ new spawn_t("func_object", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_func_object(ent);return true;}}),
+ new spawn_t("func_timer", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_func_timer(ent);return true;}}),
+ new spawn_t("func_explosive", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_func_explosive(ent);return true;}}),
+ new spawn_t("func_killbox", SP_func_killbox),
+ new spawn_t("trigger_always", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_always(ent);return true;}}),
+ new spawn_t("trigger_once", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_once(ent);return true;}}),
+ new spawn_t("trigger_multiple", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_multiple(ent);return true;}}),
+ new spawn_t("trigger_relay", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_relay(ent);return true;}}),
+ new spawn_t("trigger_push", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_push(ent);return true;}}),
+ new spawn_t("trigger_hurt", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_hurt(ent);return true;}}),
+ new spawn_t("trigger_key", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_key(ent);return true;}}),
+ new spawn_t("trigger_counter", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_trigger_counter(ent);return true;}}),
+ new spawn_t("trigger_elevator", SP_trigger_elevator ),
+ new spawn_t("trigger_gravity", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_gravity(ent);return true;}}),
+ new spawn_t("trigger_monsterjump", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_trigger_monsterjump(ent);return true;}}),
+ new spawn_t("target_temp_entity", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_temp_entity(ent);return true;}}),
+ new spawn_t("target_speaker", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_speaker(ent);return true;}}),
+ new spawn_t("target_explosion", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_explosion(ent);return true;}}),
+ new spawn_t("target_changelevel", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_changelevel(ent);return true;}}),
+ new spawn_t("target_secret", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_secret(ent);return true;}}),
+ new spawn_t("target_goal", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_goal(ent);return true;}}),
+ new spawn_t("target_splash", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_splash(ent);return true;}}),
+ new spawn_t("target_spawner", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_spawner(ent);return true;}}),
+ new spawn_t("target_blaster", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_target_blaster(ent);return true;}}),
+ new spawn_t("target_crosslevel_trigger", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_crosslevel_trigger(ent);return true;}}),
+ new spawn_t("target_crosslevel_target", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_crosslevel_target(ent);return true;}}),
+ new spawn_t("target_laser", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_laser(ent);return true;}}),
+ new spawn_t("target_help", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_help(ent);return true;}}),
+ new spawn_t("target_actor", new EntThinkAdapter() {public boolean think(edict_t ent){M_Actor.SP_target_actor(ent); return true;}}),
+ new spawn_t("target_lightramp", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_lightramp(ent);return true;}}),
+ new spawn_t("target_earthquake", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_earthquake(ent);return true;}}),
+ new spawn_t("target_character", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_target_character(ent);return true;}}),
+ new spawn_t("target_string", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_target_string(ent);return true;}}),
+ new spawn_t("worldspawn", SP_worldspawn ),
+ new spawn_t("viewthing", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_viewthing(ent);return true;}}),
+ new spawn_t("light", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_light(ent);return true;}}),
+ new spawn_t("light_mine1", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_light_mine1(ent);return true;}}),
+ new spawn_t("light_mine2", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_light_mine2(ent);return true;}}),
+ new spawn_t("info_null", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_info_null(ent);return true;}}),
+ new spawn_t("func_group", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_info_null(ent);return true;}}),
+ new spawn_t("info_notnull", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_info_notnull(ent);return true;}}),
+ new spawn_t("path_corner", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_path_corner(ent);return true;}}),
+ new spawn_t("point_combat", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_point_combat(ent);return true;}}),
+ new spawn_t("misc_explobox", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_explobox(ent);return true;}}),
+ new spawn_t("misc_banner", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_banner(ent);return true;}}),
+ new spawn_t("misc_satellite_dish", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_satellite_dish(ent);return true;}}),
+ new spawn_t("misc_actor", new EntThinkAdapter() {public boolean think(edict_t ent){M_Actor.SP_misc_actor(ent); return false;}}),
+ new spawn_t("misc_gib_arm", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_misc_gib_arm(ent);return true;}}),
+ new spawn_t("misc_gib_leg", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_gib_leg(ent);return true;}}),
+ new spawn_t("misc_gib_head", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_gib_head(ent);return true;}}),
+ new spawn_t("misc_insane", new EntThinkAdapter() {public boolean think(edict_t ent){M_Insane.SP_misc_insane(ent); return true;}}),
+ new spawn_t("misc_deadsoldier", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_deadsoldier(ent);return true;}}),
+ new spawn_t("misc_viper", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_viper(ent);return true;}}),
+ new spawn_t("misc_viper_bomb", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_misc_viper_bomb(ent);return true;}}),
+ new spawn_t("misc_bigviper", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_bigviper(ent);return true;}}),
+ new spawn_t("misc_strogg_ship", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_strogg_ship(ent);return true;}}),
+ new spawn_t("misc_teleporter", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_misc_teleporter(ent);return true;}}),
+ new spawn_t("misc_teleporter_dest", SP_misc_teleporter_dest ),
+ new spawn_t("misc_blackhole", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_misc_blackhole(ent);return true;}}),
+ new spawn_t("misc_eastertank", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_misc_eastertank(ent);return true;}}),
+ new spawn_t("misc_easterchick", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_easterchick(ent);return true;}}),
+ new spawn_t("misc_easterchick2", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_misc_easterchick2(ent);return true;}}),
+ new spawn_t("monster_berserk", new EntThinkAdapter() {public boolean think(edict_t ent){M_Berserk.SP_monster_berserk(ent);return true;}}),
+ new spawn_t("monster_gladiator", new EntThinkAdapter() {public boolean think(edict_t ent){M_Gladiator.SP_monster_gladiator(ent);return true;}}),
+ new spawn_t("monster_gunner", new EntThinkAdapter() {public boolean think(edict_t ent){M_Gunner.SP_monster_gunner(ent);return true;}}),
+ new spawn_t("monster_infantry", new EntThinkAdapter() {public boolean think(edict_t ent){M_Infantry.SP_monster_infantry(ent);return true;}}),
+ new spawn_t("monster_soldier_light", M_Soldier.SP_monster_soldier_light),
+ new spawn_t("monster_soldier", M_Soldier.SP_monster_soldier),
+ new spawn_t("monster_soldier_ss", M_Soldier.SP_monster_soldier_ss),
+ new spawn_t("monster_tank", M_Tank.SP_monster_tank),
+ new spawn_t("monster_tank_commander", M_Tank.SP_monster_tank),
+ new spawn_t("monster_medic", new EntThinkAdapter() {public boolean think(edict_t ent){M_Medic.SP_monster_medic(ent);return true;}}),
+ new spawn_t("monster_flipper", new EntThinkAdapter() {public boolean think(edict_t ent){M_Flipper.SP_monster_flipper(ent);return true;}}),
+ new spawn_t("monster_chick", new EntThinkAdapter() {public boolean think(edict_t ent){ M_Chick.SP_monster_chick(ent);return true;}}),
+ new spawn_t("monster_parasite", M_Parasite.SP_monster_parasite ),
+ new spawn_t("monster_flyer", new EntThinkAdapter() {public boolean think(edict_t ent){M_Flyer.SP_monster_flyer(ent);return true;}}),
+ new spawn_t("monster_brain", new EntThinkAdapter() {public boolean think(edict_t ent){ M_Brain.SP_monster_brain(ent);return true;}}),
+ new spawn_t("monster_floater", new EntThinkAdapter() {public boolean think(edict_t ent){M_Float.SP_monster_floater(ent);return true;}}),
+ new spawn_t("monster_hover", new EntThinkAdapter() {public boolean think(edict_t ent){ M_Hover.SP_monster_hover(ent);return true;}}),
+ new spawn_t("monster_mutant", M_Mutant.SP_monster_mutant),
+ new spawn_t("monster_supertank", M_Supertank.SP_monster_supertank),
+ new spawn_t("monster_boss2", new EntThinkAdapter() {public boolean think(edict_t ent){M_Boss2.SP_monster_boss2(ent);return true;}}),
+ new spawn_t("monster_boss3_stand", new EntThinkAdapter() {public boolean think(edict_t ent){M_Boss3.SP_monster_boss3_stand(ent);return true;}}),
+ new spawn_t("monster_jorg", new EntThinkAdapter() {public boolean think(edict_t ent){M_Boss31.SP_monster_jorg(ent);return true;}}),
+ new spawn_t("monster_commander_body", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_monster_commander_body(ent);return true;}}),
+ new spawn_t("turret_breach", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_turret_breach(ent);return true;}}),
+ new spawn_t("turret_base", new EntThinkAdapter() {public boolean think(edict_t ent){Game. SP_turret_base(ent);return true;}}),
+ new spawn_t("turret_driver", new EntThinkAdapter() {public boolean think(edict_t ent){Game.SP_turret_driver(ent);return true;}}),
+ new spawn_t(null, null)};
+ /*
+ ===============
+ ED_CallSpawn
+
+ Finds the spawn function for the entity and calls it
+ ===============
+ */
+ public static void ED_CallSpawn(edict_t ent) {
+
+ spawn_t s;
+ gitem_t item;
+ int i;
+ if (null == ent.classname) {
+ gi.dprintf("ED_CallSpawn: null classname\n");
+ return;
+ } // check item spawn functions
+ for (i = 1; i < game.num_items; i++) {
+
+ item = itemlist[i];
+
+ if (item == null)
+ gi.error("ED_CallSpawn: null item in pos " + i);
+
+ if (item.classname == null)
+ continue;
+ if (0 == Lib.strcmp(item.classname, ent.classname)) { // found it
+ SpawnItem(ent, item);
+ return;
+ }
+ } // check normal spawn functions
+
+ for (i=0; (s = spawns[i]) !=null && s.name != null; i++) {
+ if (0 == Lib.strcmp(s.name, ent.classname)) { // found it
+
+ if (s.spawn == null)
+ gi.error("ED_CallSpawn: null-spawn on index=" + i);
+ s.spawn.think(ent);
+ return;
+ }
+ }
+ gi.dprintf(ent.classname + " doesn't have a spawn function\n");
+ }
+}
diff --git a/src/jake2/game/GameTarget.java b/src/jake2/game/GameTarget.java
new file mode 100644
index 0000000..c28e1d3
--- /dev/null
+++ b/src/jake2/game/GameTarget.java
@@ -0,0 +1,829 @@
+/*
+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.1 2004-07-07 19:59:03 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.game.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class GameTarget extends GameTurret {
+
+ /*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) {
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(ent.style);
+ gi.WritePosition(ent.s.origin);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+ }
+ };
+
+ public static void SP_target_temp_entity(edict_t ent) {
+ ent.use = Use_Target_Tent;
+ }
+
+ //==========================================================
+
+ //==========================================================
+
+ /*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 = CHAN_VOICE | CHAN_RELIABLE;
+ else
+ chan = CHAN_VOICE;
+ // use a positioned_sound, because this entity won't normally be
+ // sent to any clients because it is invisible
+ gi.positioned_sound(ent.s.origin, ent, chan, ent.noise_index, ent.volume, ent.attenuation, 0);
+ }
+
+ }
+ };
+
+ 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 = 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);
+ }
+
+ //==========================================================
+ 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)
+ //strncpy(game.helpmessage1, ent.message, sizeof(game.helpmessage2) - 1);
+ ent.message = game.helpmessage1;
+ else
+ //strncpy(game.helpmessage2, ent.message, sizeof(game.helpmessage1) - 1);
+ ent.message = game.helpmessage2;
+
+ game.helpchanged++;
+ }
+ };
+
+ /*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 = Use_Target_Help;
+ }
+
+ //==========================================================
+
+ /*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) {
+ gi.sound(ent, CHAN_VOICE, ent.noise_index, 1, ATTN_NORM, 0);
+
+ level.found_secrets++;
+
+ G_UseTargets(ent, activator);
+ G_FreeEdict(ent);
+ }
+ };
+
+ public static void SP_target_secret(edict_t ent) {
+ if (deathmatch.value != 0) { // auto-remove for deathmatch
+ G_FreeEdict(ent);
+ return;
+ }
+
+ ent.use = 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.";
+ }
+
+ //==========================================================
+
+ /*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) {
+ gi.sound(ent, CHAN_VOICE, ent.noise_index, 1, ATTN_NORM, 0);
+
+ level.found_goals++;
+
+ if (level.found_goals == level.total_goals)
+ gi.configstring(CS_CDTRACK, "0");
+
+ G_UseTargets(ent, activator);
+ G_FreeEdict(ent);
+ }
+ };
+
+ public static void SP_target_goal(edict_t ent) {
+ if (deathmatch.value != 0) { // auto-remove for deathmatch
+ G_FreeEdict(ent);
+ return;
+ }
+
+ ent.use = 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++;
+ }
+
+ //==========================================================
+
+ /*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;
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_EXPLOSION1);
+ gi.WritePosition(self.s.origin);
+ gi.multicast(self.s.origin, MULTICAST_PHS);
+
+ T_RadiusDamage(self, self.activator, self.dmg, null, self.dmg + 40, MOD_EXPLOSIVE);
+
+ save = self.delay;
+ self.delay = 0;
+ 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 = level.time + self.delay;
+ }
+ };
+
+ public static void SP_target_explosion(edict_t ent) {
+ ent.use = use_target_explosion;
+ ent.svflags = SVF_NOCLIENT;
+ }
+
+ //==========================================================
+
+ /*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 (level.intermissiontime != 0)
+ return; // already activated
+
+ if (0 == deathmatch.value && 0 == coop.value) {
+ if (g_edicts[1].health <= 0)
+ return;
+ }
+
+ // if noexit, do a ton of damage to other
+ if (deathmatch.value != 0 && 0 == ((int) dmflags.value & DF_ALLOW_EXIT) && other != g_edicts[0] /*world*/
+ ) {
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, 10 * other.max_health, 1000, 0, MOD_EXIT);
+ return;
+ }
+
+ // if multiplayer, let everyone know who hit the exit
+ if (deathmatch.value != 0) {
+ if (activator != null && activator.client != null)
+ gi.bprintf(PRINT_HIGH, activator.client.pers.netname + " exited the level.\n");
+ }
+
+ // if going to a new unit, clear cross triggers
+ if (self.map.indexOf('*') > -1)
+ game.serverflags &= ~(SFL_CROSS_TRIGGER_MASK);
+
+ PlayerHud.BeginIntermission(self);
+ }
+ };
+
+ 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 = use_target_changelevel;
+ ent.svflags = SVF_NOCLIENT;
+ }
+
+ //==========================================================
+
+ /*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) {
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_SPLASH);
+ gi.WriteByte(self.count);
+ gi.WritePosition(self.s.origin);
+ gi.WriteDir(self.movedir);
+ gi.WriteByte(self.sounds);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+
+ if (self.dmg != 0)
+ T_RadiusDamage(self, activator, self.dmg, null, self.dmg + 40, MOD_SPLASH);
+ }
+ };
+
+ public static void SP_target_splash(edict_t self) {
+ self.use = use_target_splash;
+ G_SetMovedir(self.s.angles, self.movedir);
+
+ if (0 == self.count)
+ self.count = 32;
+
+ self.svflags = SVF_NOCLIENT;
+ }
+
+ //==========================================================
+
+ /*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 = G_Spawn();
+ ent.classname = self.target;
+ VectorCopy(self.s.origin, ent.s.origin);
+ VectorCopy(self.s.angles, ent.s.angles);
+ GameSpawn.ED_CallSpawn(ent);
+ gi.unlinkentity(ent);
+ KillBox(ent);
+ gi.linkentity(ent);
+ if (self.speed != 0)
+ VectorCopy(self.movedir, ent.velocity);
+ }
+ };
+
+ public static void SP_target_spawner(edict_t self) {
+ self.use = 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);
+ }
+ }
+
+ //==========================================================
+
+ /*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 = EF_HYPERBLASTER;
+ else
+ effect = EF_BLASTER;
+
+ Fire.fire_blaster(self, self.s.origin, self.movedir, self.dmg, (int) self.speed, EF_BLASTER, MOD_TARGET_BLASTER != 0
+ /*true*/
+ );
+ gi.sound(self, CHAN_VOICE, self.noise_index, 1, ATTN_NORM, 0);
+ }
+ };
+
+ public static void SP_target_blaster(edict_t self) {
+ self.use = 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;
+ }
+
+ //==========================================================
+
+ /*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) {
+ game.serverflags |= self.spawnflags;
+ G_FreeEdict(self);
+ }
+ };
+
+ public static void SP_target_crosslevel_trigger(edict_t self) {
+ self.svflags = SVF_NOCLIENT;
+ self.use = trigger_crosslevel_trigger_use;
+ }
+
+ /*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 == (game.serverflags & SFL_CROSS_TRIGGER_MASK & self.spawnflags)) {
+ G_UseTargets(self, self);
+ G_FreeEdict(self);
+ }
+ return true;
+ }
+ };
+
+ public static void SP_target_crosslevel_target(edict_t self) {
+ if (0 == self.delay)
+ self.delay = 1;
+ self.svflags = SVF_NOCLIENT;
+
+ self.think = target_crosslevel_target_think;
+ self.nextthink = level.time + self.delay;
+ }
+
+ //==========================================================
+
+ /*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) {
+ VectorCopy(self.movedir, last_movedir);
+ VectorMA(self.enemy.absmin, 0.5f, self.enemy.size, point);
+ VectorSubtract(point, self.s.origin, self.movedir);
+ VectorNormalize(self.movedir);
+ if (0 == VectorCompare(self.movedir, last_movedir))
+ self.spawnflags |= 0x80000000;
+ }
+
+ ignore = self;
+ VectorCopy(self.s.origin, start);
+ VectorMA(start, 2048, self.movedir, end);
+ while (true) {
+ tr = gi.trace(start, null, null, end, ignore, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_DEADMONSTER);
+
+ if (tr.ent == null)
+ break;
+
+ // hurt it if we can
+ if ((tr.ent.takedamage != 0) && 0 == (tr.ent.flags & FL_IMMUNE_LASER))
+ T_Damage(
+ tr.ent,
+ self,
+ self.activator,
+ self.movedir,
+ tr.endpos,
+ vec3_origin,
+ self.dmg,
+ 1,
+ DAMAGE_ENERGY,
+ 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 & SVF_MONSTER) && (null == tr.ent.client)) {
+ if ((self.spawnflags & 0x80000000) != 0) {
+ self.spawnflags &= ~0x80000000;
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_LASER_SPARKS);
+ gi.WriteByte(count);
+ gi.WritePosition(tr.endpos);
+ gi.WriteDir(tr.plane.normal);
+ gi.WriteByte(self.s.skinnum);
+ gi.multicast(tr.endpos, MULTICAST_PVS);
+ }
+ break;
+ }
+
+ ignore = tr.ent;
+ VectorCopy(tr.endpos, start);
+ }
+
+ VectorCopy(tr.endpos, self.s.old_origin);
+
+ self.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+ public static void target_laser_on(edict_t self) {
+ if (null == self.activator)
+ self.activator = self;
+ self.spawnflags |= 0x80000001;
+ self.svflags &= ~SVF_NOCLIENT;
+ 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 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)
+ target_laser_off(self);
+ else
+ target_laser_on(self);
+ }
+ };
+
+ static EntThinkAdapter target_laser_start = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ edict_t ent;
+
+ self.movetype = MOVETYPE_NONE;
+ self.solid = SOLID_NOT;
+ self.s.renderfx |= RF_BEAM | 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 = G_Find(null, findByTarget, self.target).o;
+ if (ent == null)
+ gi.dprintf(self.classname + " at " + vtos(self.s.origin) + ": " + self.target + " is a bad target\n");
+ self.enemy = ent;
+ }
+ else {
+ G_SetMovedir(self.s.angles, self.movedir);
+ }
+ }
+ self.use = target_laser_use;
+ self.think = target_laser_think;
+
+ if (0 == self.dmg)
+ self.dmg = 1;
+
+ VectorSet(self.mins, -8, -8, -8);
+ VectorSet(self.maxs, 8, 8, 8);
+ gi.linkentity(self);
+
+ if ((self.spawnflags & 1) != 0)
+ target_laser_on(self);
+ else
+ target_laser_off(self);
+ return true;
+ }
+ };
+
+ public static void SP_target_laser(edict_t self) {
+ // let everything else get spawned before we start firing
+ self.think = target_laser_start;
+ self.nextthink = level.time + 1;
+ }
+
+ //==========================================================
+
+ /*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] + (level.time - self.timestamp) / FRAMETIME * self.movedir[2]));
+ style[1] = 0;
+ gi.configstring(CS_LIGHTS + self.enemy.style, new String(style));
+
+ if ((level.time - self.timestamp) < self.speed) {
+ self.nextthink = level.time + 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 = G_Find(es, findByTarget, self.target);
+ e = es.o;
+
+ if (e == null)
+ break;
+ if (strcmp(e.classname, "light") != 0) {
+ gi.dprintf(self.classname + " at " + vtos(self.s.origin));
+ gi.dprintf("target " + self.target + " (" + e.classname + " at " + vtos(e.s.origin) + ") is not a light\n");
+ }
+ else {
+ self.enemy = e;
+ }
+ }
+
+ if (null == self.enemy) {
+ gi.dprintf(self.classname + " target " + self.target + " not found at " + vtos(self.s.origin) + "\n");
+ G_FreeEdict(self);
+ return;
+ }
+ }
+
+ self.timestamp = level.time;
+ target_lightramp_think.think(self);
+ }
+ };
+
+ public static void SP_target_lightramp(edict_t self) {
+ if (self.message == null
+ || strlen(self.message) != 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 = target_lightramp_use;
+ self.think = 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);
+ }
+
+ //==========================================================
+
+ /*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 < level.time) {
+ gi.positioned_sound(self.s.origin, self, CHAN_AUTO, self.noise_index, 1.0f, ATTN_NONE, 0);
+ self.last_move_time = level.time + 0.5f;
+ }
+
+ for (i = 1; i < globals.num_edicts; i++) {
+ e = g_edicts[i];
+
+ if (!e.inuse)
+ continue;
+ if (null == e.client)
+ continue;
+ if (null == e.groundentity)
+ continue;
+
+ e.groundentity = null;
+ e.velocity[0] += crandom() * 150;
+ e.velocity[1] += crandom() * 150;
+ e.velocity[2] = self.speed * (100.0f / e.mass);
+ }
+
+ if (level.time < self.timestamp)
+ self.nextthink = level.time + FRAMETIME;
+
+ return true;
+ }
+ };
+
+ static EntUseAdapter target_earthquake_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.timestamp = level.time + self.count;
+ self.nextthink = level.time + FRAMETIME;
+ self.activator = activator;
+ self.last_move_time = 0;
+ }
+ };
+
+ 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 = target_earthquake_think;
+ self.use = target_earthquake_use;
+
+ self.noise_index = gi.soundindex("world/quake.wav");
+ }
+
+}
diff --git a/src/jake2/game/GameTrigger.java b/src/jake2/game/GameTrigger.java
new file mode 100644
index 0000000..c4bac9e
--- /dev/null
+++ b/src/jake2/game/GameTrigger.java
@@ -0,0 +1,574 @@
+/*
+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 27.12.2003 by RST.
+// $Id: GameTrigger.java,v 1.1 2004-07-07 19:59:03 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+import jake2.util.Math3D;
+
+public class GameTrigger extends GamePWeapon {
+
+ public static void InitTrigger(edict_t self) {
+ if (Math3D.VectorCompare(self.s.angles, vec3_origin) != 0)
+ G_SetMovedir(self.s.angles, self.movedir);
+
+ self.solid = SOLID_TRIGGER;
+ self.movetype = MOVETYPE_NONE;
+ gi.setmodel(self, self.model);
+ self.svflags = SVF_NOCLIENT;
+ }
+
+ // the wait time has passed, so set back up for another activation
+ public static EntThinkAdapter multi_wait = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+
+ ent.nextthink = 0;
+ return true;
+ }
+ };
+
+ // the trigger was just activated
+ // ent.activator should be set to the activator so it can be held through a delay
+ // so wait for the delay time before firing
+ public static void multi_trigger(edict_t ent) {
+ if (ent.nextthink != 0)
+ return; // already been triggered
+
+ G_UseTargets(ent, ent.activator);
+
+ if (ent.wait > 0) {
+ ent.think = multi_wait;
+ ent.nextthink = level.time + ent.wait;
+ }
+ else { // we can't just remove (self) here, because this is a touch function
+ // called while looping through area links...
+ ent.touch = null;
+ ent.nextthink = level.time + FRAMETIME;
+ ent.think = G_FreeEdictA;
+ }
+ }
+
+ static EntUseAdapter Use_Multi = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ ent.activator = activator;
+ multi_trigger(ent);
+ }
+ };
+
+ static EntTouchAdapter Touch_Multi = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (other.client != null) {
+ if ((self.spawnflags & 2) != 0)
+ return;
+ }
+ else if ((other.svflags & SVF_MONSTER) != 0) {
+ if (0 == (self.spawnflags & 1))
+ return;
+ }
+ else
+ return;
+
+ if (0 == VectorCompare(self.movedir, vec3_origin)) {
+ float[] forward = { 0, 0, 0 };
+
+ AngleVectors(other.s.angles, forward, null, null);
+ if (DotProduct(forward, self.movedir) < 0)
+ return;
+ }
+
+ self.activator = other;
+ multi_trigger(self);
+ }
+ };
+
+ /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
+ Variable sized repeatable trigger. Must be targeted at one or more entities.
+ If "delay" is set, the trigger waits some time after activating before firing.
+ "wait" : Seconds between triggerings. (.2 default)
+ sounds
+ 1) secret
+ 2) beep beep
+ 3) large switch
+ 4)
+ set "message" to text string
+ */
+ static EntUseAdapter trigger_enable = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.solid = SOLID_TRIGGER;
+ self.use = Use_Multi;
+ gi.linkentity(self);
+ }
+ };
+ public static void SP_trigger_multiple(edict_t ent) {
+ if (ent.sounds == 1)
+ ent.noise_index = gi.soundindex("misc/secret.wav");
+ else if (ent.sounds == 2)
+ ent.noise_index = gi.soundindex("misc/talk.wav");
+ else if (ent.sounds == 3)
+ ent.noise_index = gi.soundindex("misc/trigger1.wav");
+
+ if (ent.wait == 0)
+ ent.wait = 0.2f;
+
+ ent.touch = Touch_Multi;
+ ent.movetype = MOVETYPE_NONE;
+ ent.svflags |= SVF_NOCLIENT;
+
+ if ((ent.spawnflags & 4) != 0) {
+ ent.solid = SOLID_NOT;
+ ent.use = trigger_enable;
+ }
+ else {
+ ent.solid = SOLID_TRIGGER;
+ ent.use = Use_Multi;
+ }
+
+ if (0 == Math3D.VectorCompare(ent.s.angles, vec3_origin))
+ G_SetMovedir(ent.s.angles, ent.movedir);
+
+ gi.setmodel(ent, ent.model);
+ gi.linkentity(ent);
+ }
+
+ /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
+ Triggers once, then removes itself.
+ You must set the key "target" to the name of another object in the level that has a matching "targetname".
+
+ If TRIGGERED, this trigger must be triggered before it is live.
+
+ sounds
+ 1) secret
+ 2) beep beep
+ 3) large switch
+ 4)
+
+ "message" string to be displayed when triggered
+ */
+
+ public static void SP_trigger_once(edict_t ent) {
+ // make old maps work because I messed up on flag assignments here
+ // triggered was on bit 1 when it should have been on bit 4
+ if ((ent.spawnflags & 1) != 0) {
+ float[] v = { 0, 0, 0 };
+
+ VectorMA(ent.mins, 0.5f, ent.size, v);
+ ent.spawnflags &= ~1;
+ ent.spawnflags |= 4;
+ gi.dprintf("fixed TRIGGERED flag on " + ent.classname + " at " + vtos(v) + "\n");
+ }
+
+ ent.wait = -1;
+ SP_trigger_multiple(ent);
+ }
+
+ /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
+ This fixed size trigger cannot be touched, it can only be fired by other events.
+ */
+ public static EntUseAdapter trigger_relay_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ G_UseTargets(self, activator);
+ }
+ };
+
+ public static void SP_trigger_relay(edict_t self) {
+ self.use = trigger_relay_use;
+ }
+
+ /*
+ ==============================================================================
+
+ trigger_key
+
+ ==============================================================================
+ */
+
+ /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
+ A relay trigger that only fires it's targets if player has the proper key.
+ Use "item" to specify the required key, for example "key_data_cd"
+ */
+
+ static EntUseAdapter trigger_key_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ int index;
+
+ if (self.item == null)
+ return;
+ if (activator.client == null)
+ return;
+
+ index = ITEM_INDEX(self.item);
+ if (activator.client.pers.inventory[index] == 0) {
+ if (level.time < self.touch_debounce_time)
+ return;
+ self.touch_debounce_time = level.time + 5.0f;
+ gi.centerprintf(activator, "You need the " + self.item.pickup_name);
+ gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/keytry.wav"), 1, ATTN_NORM, 0);
+ return;
+ }
+
+ gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/keyuse.wav"), 1, ATTN_NORM, 0);
+ if (coop.value != 0) {
+ int player;
+ edict_t ent;
+
+ if (strcmp(self.item.classname, "key_power_cube") == 0) {
+ int cube;
+
+ for (cube = 0; cube < 8; cube++)
+ if ((activator.client.pers.power_cubes & (1 << cube)) != 0)
+ break;
+ for (player = 1; player <= game.maxclients; player++) {
+ ent = g_edicts[player];
+ if (!ent.inuse)
+ continue;
+ if (null == ent.client)
+ continue;
+ if ((ent.client.pers.power_cubes & (1 << cube)) != 0) {
+ ent.client.pers.inventory[index]--;
+ ent.client.pers.power_cubes &= ~(1 << cube);
+ }
+ }
+ }
+ else {
+ for (player = 1; player <= game.maxclients; player++) {
+ ent = g_edicts[player];
+ if (!ent.inuse)
+ continue;
+ if (ent.client == null)
+ continue;
+ ent.client.pers.inventory[index] = 0;
+ }
+ }
+ }
+ else {
+ activator.client.pers.inventory[index]--;
+ }
+
+ G_UseTargets(self, activator);
+
+ self.use = null;
+ }
+ };
+
+ public static void SP_trigger_key(edict_t self) {
+ if (st.item == null) {
+ gi.dprintf("no key item for trigger_key at " + vtos(self.s.origin) + "\n");
+ return;
+ }
+ self.item = FindItemByClassname(st.item);
+
+ if (null == self.item) {
+ gi.dprintf("item " + st.item + " not found for trigger_key at " + vtos(self.s.origin) + "\n");
+ return;
+ }
+
+ if (self.target == null) {
+ gi.dprintf(self.classname + " at " + vtos(self.s.origin) + " has no target\n");
+ return;
+ }
+
+ gi.soundindex("misc/keytry.wav");
+ gi.soundindex("misc/keyuse.wav");
+
+ self.use = trigger_key_use;
+ }
+
+ /*
+ ==============================================================================
+
+ trigger_counter
+
+ ==============================================================================
+ */
+
+ /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
+ Acts as an intermediary for an action that takes multiple inputs.
+
+ If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
+
+ After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
+ */
+ static EntUseAdapter trigger_counter_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (self.count == 0)
+ return;
+
+ self.count--;
+
+ if (self.count == 0) {
+ if (0 == (self.spawnflags & 1)) {
+ gi.centerprintf(activator, self.count + " more to go...");
+ gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
+ }
+ return;
+ }
+
+ if (0 == (self.spawnflags & 1)) {
+ gi.centerprintf(activator, "Sequence completed!");
+ gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
+ }
+ self.activator = activator;
+ multi_trigger(self);
+ }
+ };
+
+ public static void SP_trigger_counter(edict_t self) {
+ self.wait = -1;
+ if (0 == self.count)
+ self.count = 2;
+
+ self.use = trigger_counter_use;
+ }
+
+ /*
+ ==============================================================================
+
+ trigger_always
+
+ ==============================================================================
+ */
+
+ /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
+ This trigger will always fire. It is activated by the world.
+ */
+ public static void SP_trigger_always(edict_t ent) {
+ // we must have some delay to make sure our use targets are present
+ if (ent.delay < 0.2f)
+ ent.delay = 0.2f;
+ G_UseTargets(ent, ent);
+ }
+
+ /*
+ ==============================================================================
+
+ trigger_push
+
+ ==============================================================================
+ */
+
+ public static final int PUSH_ONCE = 1;
+
+ public static int windsound;
+
+ static EntTouchAdapter trigger_push_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (strcmp(other.classname, "grenade") == 0) {
+ VectorScale(self.movedir, self.speed * 10, other.velocity);
+ }
+ else if (other.health > 0) {
+ VectorScale(self.movedir, self.speed * 10, other.velocity);
+
+ if (other.client != null) {
+ // don't take falling damage immediately from this
+ VectorCopy(other.velocity, other.client.oldvelocity);
+ if (other.fly_sound_debounce_time < level.time) {
+ other.fly_sound_debounce_time = level.time + 1.5f;
+ gi.sound(other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
+ }
+ }
+ }
+ if ((self.spawnflags & PUSH_ONCE) != 0)
+ G_FreeEdict(self);
+ }
+ };
+
+ /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
+ Pushes the player
+ "speed" defaults to 1000
+ */
+ public static void SP_trigger_push(edict_t self) {
+ InitTrigger(self);
+ windsound = gi.soundindex("misc/windfly.wav");
+ self.touch = trigger_push_touch;
+ if (0 == self.speed)
+ self.speed = 1000;
+ gi.linkentity(self);
+ }
+
+ /*
+ ==============================================================================
+
+ trigger_hurt
+
+ ==============================================================================
+ */
+
+ /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
+ Any entity that touches this will be hurt.
+
+ It does dmg points of damage each server frame
+
+ SILENT supresses playing the sound
+ SLOW changes the damage rate to once per second
+ NO_PROTECTION *nothing* stops the damage
+
+ "dmg" default 5 (whole numbers only)
+
+ */
+ static EntUseAdapter hurt_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (self.solid == SOLID_NOT)
+ self.solid = SOLID_TRIGGER;
+ else
+ self.solid = SOLID_NOT;
+ gi.linkentity(self);
+
+ if (0 == (self.spawnflags & 2))
+ self.use = null;
+ }
+ };
+ static EntTouchAdapter hurt_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ int dflags;
+
+ if (other.takedamage == 0)
+ return;
+
+ if (self.timestamp > level.time)
+ return;
+
+ if ((self.spawnflags & 16) != 0)
+ self.timestamp = level.time + 1;
+ else
+ self.timestamp = level.time + FRAMETIME;
+
+ if (0 == (self.spawnflags & 4)) {
+ if ((level.framenum % 10) == 0)
+ gi.sound(other, CHAN_AUTO, self.noise_index, 1, ATTN_NORM, 0);
+ }
+
+ if ((self.spawnflags & 8) != 0)
+ dflags = DAMAGE_NO_PROTECTION;
+ else
+ dflags = 0;
+ T_Damage(other, self, self, vec3_origin, other.s.origin, vec3_origin, self.dmg, self.dmg, dflags, MOD_TRIGGER_HURT);
+ }
+ };
+
+ public static void SP_trigger_hurt(edict_t self) {
+ InitTrigger(self);
+
+ self.noise_index = gi.soundindex("world/electro.wav");
+ self.touch = hurt_touch;
+
+ if (0 == self.dmg)
+ self.dmg = 5;
+
+ if ((self.spawnflags & 1) != 0)
+ self.solid = SOLID_NOT;
+ else
+ self.solid = SOLID_TRIGGER;
+
+ if ((self.spawnflags & 2) != 0)
+ self.use = hurt_use;
+
+ gi.linkentity(self);
+ }
+
+ /*
+ ==============================================================================
+
+ trigger_gravity
+
+ ==============================================================================
+ */
+
+ /*QUAKED trigger_gravity (.5 .5 .5) ?
+ Changes the touching entites gravity to
+ the value of "gravity". 1.0 is standard
+ gravity for the level.
+ */
+
+ static EntTouchAdapter trigger_gravity_touch = new EntTouchAdapter() {
+
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ other.gravity = self.gravity;
+ }
+ };
+
+ public static void SP_trigger_gravity(edict_t self) {
+ if (st.gravity == null) {
+ gi.dprintf("trigger_gravity without gravity set at " + vtos(self.s.origin) + "\n");
+ G_FreeEdict(self);
+ return;
+ }
+
+ InitTrigger(self);
+ self.gravity = atoi(st.gravity);
+ self.touch = trigger_gravity_touch;
+ }
+
+ /*
+ ==============================================================================
+
+ trigger_monsterjump
+
+ ==============================================================================
+ */
+
+ /*QUAKED trigger_monsterjump (.5 .5 .5) ?
+ Walking monsters that touch this will jump in the direction of the trigger's angle
+ "speed" default to 200, the speed thrown forward
+ "height" default to 200, the speed thrown upwards
+ */
+
+ static EntTouchAdapter trigger_monsterjump_touch = new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if ((other.flags & (FL_FLY | FL_SWIM)) != 0)
+ return;
+ if ((other.svflags & SVF_DEADMONSTER) != 0)
+ return;
+ if (0 == (other.svflags & SVF_MONSTER))
+ return;
+
+ // set XY even if not on ground, so the jump will clear lips
+ other.velocity[0] = self.movedir[0] * self.speed;
+ other.velocity[1] = self.movedir[1] * self.speed;
+
+ if (other.groundentity != null)
+ return;
+
+ other.groundentity = null;
+ other.velocity[2] = self.movedir[2];
+ }
+ };
+
+ public static void SP_trigger_monsterjump(edict_t self) {
+ if (0 == self.speed)
+ self.speed = 200;
+ if (0 == st.height)
+ st.height = 200;
+ if (self.s.angles[YAW] == 0)
+ self.s.angles[YAW] = 360;
+ InitTrigger(self);
+ self.touch = trigger_monsterjump_touch;
+ self.movedir[2] = st.height;
+ }
+
+}
diff --git a/src/jake2/game/GameTurret.java b/src/jake2/game/GameTurret.java
new file mode 100644
index 0000000..fd22a37
--- /dev/null
+++ b/src/jake2/game/GameTurret.java
@@ -0,0 +1,430 @@
+/*
+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: GameTurret.java,v 1.1 2004-07-07 19:59:04 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.game.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class GameTurret extends GameMisc {
+
+ public static void AnglesNormalize(float[] vec) {
+ while (vec[0] > 360)
+ vec[0] -= 360;
+ while (vec[0] < 0)
+ vec[0] += 360;
+ while (vec[1] > 360)
+ vec[1] -= 360;
+ while (vec[1] < 0)
+ vec[1] += 360;
+ }
+
+ public static float SnapToEights(float x) {
+ x *= 8.0;
+ if (x > 0.0)
+ x += 0.5;
+ else
+ x -= 0.5;
+ return 0.125f * (int) x;
+ }
+
+ static EntBlockedAdapter turret_blocked = new EntBlockedAdapter() {
+
+ public void blocked(edict_t self, edict_t other) {
+ edict_t attacker;
+
+ if (other.takedamage != 0) {
+ if (self.teammaster.owner != null)
+ attacker = self.teammaster.owner;
+ else
+ attacker = self.teammaster;
+ T_Damage(other, self, attacker, vec3_origin, other.s.origin, vec3_origin, self.teammaster.dmg, 10, 0, MOD_CRUSH);
+ }
+ }
+ };
+
+ /*QUAKED turret_breach (0 0 0) ?
+ This portion of the turret can change both pitch and yaw.
+ The model should be made with a flat pitch.
+ It (and the associated base) need to be oriented towards 0.
+ Use "angle" to set the starting angle.
+
+ "speed" default 50
+ "dmg" default 10
+ "angle" point this forward
+ "target" point this at an info_notnull at the muzzle tip
+ "minpitch" min acceptable pitch angle : default -30
+ "maxpitch" max acceptable pitch angle : default 30
+ "minyaw" min acceptable yaw angle : default 0
+ "maxyaw" max acceptable yaw angle : default 360
+ */
+
+ public static void turret_breach_fire(edict_t self) {
+ float[] f = { 0, 0, 0 }, r = { 0, 0, 0 }, u = { 0, 0, 0 };
+ float[] start = { 0, 0, 0 };
+ int damage;
+ int speed;
+
+ AngleVectors(self.s.angles, f, r, u);
+ VectorMA(self.s.origin, self.move_origin[0], f, start);
+ VectorMA(start, self.move_origin[1], r, start);
+ VectorMA(start, self.move_origin[2], u, start);
+
+ damage = (int) (100 + random() * 50);
+ speed = (int) (550 + 50 * skill.value);
+ Fire.fire_rocket(self.teammaster.owner, start, f, damage, speed, 150, damage);
+ gi.positioned_sound(start, self, CHAN_WEAPON, gi.soundindex("weapons/rocklf1a.wav"), 1, ATTN_NORM, 0);
+ }
+
+ static EntThinkAdapter turret_breach_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ edict_t ent;
+ float[] current_angles = { 0, 0, 0 };
+ float[] delta = { 0, 0, 0 };
+
+ VectorCopy(self.s.angles, current_angles);
+ AnglesNormalize(current_angles);
+
+ AnglesNormalize(self.move_angles);
+ if (self.move_angles[PITCH] > 180)
+ self.move_angles[PITCH] -= 360;
+
+ // clamp angles to mins & maxs
+ if (self.move_angles[PITCH] > self.pos1[PITCH])
+ self.move_angles[PITCH] = self.pos1[PITCH];
+ else if (self.move_angles[PITCH] < self.pos2[PITCH])
+ self.move_angles[PITCH] = self.pos2[PITCH];
+
+ if ((self.move_angles[YAW] < self.pos1[YAW]) || (self.move_angles[YAW] > self.pos2[YAW])) {
+ float dmin, dmax;
+
+ dmin = Math.abs(self.pos1[YAW] - self.move_angles[YAW]);
+ if (dmin < -180)
+ dmin += 360;
+ else if (dmin > 180)
+ dmin -= 360;
+ dmax = Math.abs(self.pos2[YAW] - self.move_angles[YAW]);
+ if (dmax < -180)
+ dmax += 360;
+ else if (dmax > 180)
+ dmax -= 360;
+ if (Math.abs(dmin) < Math.abs(dmax))
+ self.move_angles[YAW] = self.pos1[YAW];
+ else
+ self.move_angles[YAW] = self.pos2[YAW];
+ }
+
+ VectorSubtract(self.move_angles, current_angles, delta);
+ if (delta[0] < -180)
+ delta[0] += 360;
+ else if (delta[0] > 180)
+ delta[0] -= 360;
+ if (delta[1] < -180)
+ delta[1] += 360;
+ else if (delta[1] > 180)
+ delta[1] -= 360;
+ delta[2] = 0;
+
+ if (delta[0] > self.speed * FRAMETIME)
+ delta[0] = self.speed * FRAMETIME;
+ if (delta[0] < -1 * self.speed * FRAMETIME)
+ delta[0] = -1 * self.speed * FRAMETIME;
+ if (delta[1] > self.speed * FRAMETIME)
+ delta[1] = self.speed * FRAMETIME;
+ if (delta[1] < -1 * self.speed * FRAMETIME)
+ delta[1] = -1 * self.speed * FRAMETIME;
+
+ VectorScale(delta, 1.0f / FRAMETIME, self.avelocity);
+
+ self.nextthink = level.time + FRAMETIME;
+
+ for (ent = self.teammaster; ent != null; ent = ent.teamchain)
+ ent.avelocity[1] = self.avelocity[1];
+
+ // if we have adriver, adjust his velocities
+ if (self.owner != null) {
+ float angle;
+ float target_z;
+ float diff;
+ float[] target = { 0, 0, 0 };
+ float[] dir = { 0, 0, 0 };
+
+ // angular is easy, just copy ours
+ self.owner.avelocity[0] = self.avelocity[0];
+ self.owner.avelocity[1] = self.avelocity[1];
+
+ // x & y
+ angle = self.s.angles[1] + self.owner.move_origin[1];
+ angle *= (Math.PI * 2 / 360);
+ target[0] = SnapToEights((float) (self.s.origin[0] + Math.cos(angle) * self.owner.move_origin[0]));
+ target[1] = SnapToEights((float) (self.s.origin[1] + Math.sin(angle) * self.owner.move_origin[0]));
+ target[2] = self.owner.s.origin[2];
+
+ VectorSubtract(target, self.owner.s.origin, dir);
+ self.owner.velocity[0] = dir[0] * 1.0f / FRAMETIME;
+ self.owner.velocity[1] = dir[1] * 1.0f / FRAMETIME;
+
+ // z
+ angle = self.s.angles[PITCH] * (float) (Math.PI * 2f / 360f);
+ target_z =
+ SnapToEights((float) (self.s.origin[2] + self.owner.move_origin[0] * Math.tan(angle) + self.owner.move_origin[2]));
+
+ diff = target_z - self.owner.s.origin[2];
+ self.owner.velocity[2] = diff * 1.0f / FRAMETIME;
+
+ if ((self.spawnflags & 65536) != 0) {
+ turret_breach_fire(self);
+ self.spawnflags &= ~65536;
+ }
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter turret_breach_finish_init = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ // get and save info for muzzle location
+ if (self.target == null) {
+ gi.dprintf(self.classname + " at " + vtos(self.s.origin) + " needs a target\n");
+ }
+ else {
+ self.target_ent = G_PickTarget(self.target);
+ VectorSubtract(self.target_ent.s.origin, self.s.origin, self.move_origin);
+ G_FreeEdict(self.target_ent);
+ }
+
+ self.teammaster.dmg = self.dmg;
+ self.think = turret_breach_think;
+ self.think.think(self);
+ return true;
+ }
+ };
+
+ public static void SP_turret_breach(edict_t self) {
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_PUSH;
+ gi.setmodel(self, self.model);
+
+ if (self.speed == 0)
+ self.speed = 50;
+ if (self.dmg == 0)
+ self.dmg = 10;
+
+ if (st.minpitch == 0)
+ st.minpitch = -30;
+ if (st.maxpitch == 0)
+ st.maxpitch = 30;
+ if (st.maxyaw == 0)
+ st.maxyaw = 360;
+
+ self.pos1[PITCH] = -1 * st.minpitch;
+ self.pos1[YAW] = st.minyaw;
+ self.pos2[PITCH] = -1 * st.maxpitch;
+ self.pos2[YAW] = st.maxyaw;
+
+ self.ideal_yaw = self.s.angles[YAW];
+ self.move_angles[YAW] = self.ideal_yaw;
+
+ self.blocked = turret_blocked;
+
+ self.think = turret_breach_finish_init;
+ self.nextthink = level.time + FRAMETIME;
+ gi.linkentity(self);
+ }
+
+ /*QUAKED turret_base (0 0 0) ?
+ This portion of the turret changes yaw only.
+ MUST be teamed with a turret_breach.
+ */
+
+ public static void SP_turret_base(edict_t self) {
+ self.solid = SOLID_BSP;
+ self.movetype = MOVETYPE_PUSH;
+ gi.setmodel(self, self.model);
+ self.blocked = turret_blocked;
+ gi.linkentity(self);
+ }
+
+ /*QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32)
+ Must NOT be on the team with the rest of the turret parts.
+ Instead it must target the turret_breach.
+ */
+ static EntDieAdapter turret_driver_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+
+ edict_t ent;
+
+ // level the gun
+ self.target_ent.move_angles[0] = 0;
+
+ // remove the driver from the end of them team chain
+ for (ent = self.target_ent.teammaster; ent.teamchain != self; ent = ent.teamchain);
+ ent.teamchain = null;
+ self.teammaster = null;
+ self.flags &= ~FL_TEAMSLAVE;
+
+ self.target_ent.owner = null;
+ self.target_ent.teammaster.owner = null;
+
+ //TODO: null appended as last missing argument, was unclean. rst
+ M_Infantry.infantry_die.die(self, inflictor, attacker, damage, null);
+ }
+ };
+
+ static EntThinkAdapter turret_driver_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] target = { 0, 0, 0 };
+ float[] dir = { 0, 0, 0 };
+ float reaction_time;
+
+ self.nextthink = level.time + FRAMETIME;
+
+ if (self.enemy != null && (!self.enemy.inuse || self.enemy.health <= 0))
+ self.enemy = null;
+
+ if (null == self.enemy) {
+ if (!FindTarget(self))
+ return true;
+ self.monsterinfo.trail_time = level.time;
+ self.monsterinfo.aiflags &= ~AI_LOST_SIGHT;
+ }
+ else {
+ if (visible(self, self.enemy)) {
+ if ((self.monsterinfo.aiflags & AI_LOST_SIGHT) != 0) {
+ self.monsterinfo.trail_time = level.time;
+ self.monsterinfo.aiflags &= ~AI_LOST_SIGHT;
+ }
+ }
+ else {
+ self.monsterinfo.aiflags |= AI_LOST_SIGHT;
+ return true;
+ }
+ }
+
+ // let the turret know where we want it to aim
+ VectorCopy(self.enemy.s.origin, target);
+ target[2] += self.enemy.viewheight;
+ VectorSubtract(target, self.target_ent.s.origin, dir);
+ vectoangles(dir, self.target_ent.move_angles);
+
+ // decide if we should shoot
+ if (level.time < self.monsterinfo.attack_finished)
+ return true;
+
+ reaction_time = (3 - skill.value) * 1.0f;
+ if ((level.time - self.monsterinfo.trail_time) < reaction_time)
+ return true;
+
+ self.monsterinfo.attack_finished = level.time + reaction_time + 1.0f;
+ //FIXME how do we really want to pass this along?
+ self.target_ent.spawnflags |= 65536;
+ return true;
+ }
+ };
+
+ public static EntThinkAdapter turret_driver_link = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] vec = { 0, 0, 0 };
+ edict_t ent;
+
+ self.think = turret_driver_think;
+ self.nextthink = level.time + FRAMETIME;
+
+ self.target_ent = G_PickTarget(self.target);
+ self.target_ent.owner = self;
+ self.target_ent.teammaster.owner = self;
+ VectorCopy(self.target_ent.s.angles, self.s.angles);
+
+ vec[0] = self.target_ent.s.origin[0] - self.s.origin[0];
+ vec[1] = self.target_ent.s.origin[1] - self.s.origin[1];
+ vec[2] = 0;
+ self.move_origin[0] = VectorLength(vec);
+
+ VectorSubtract(self.s.origin, self.target_ent.s.origin, vec);
+ vectoangles(vec, vec);
+ AnglesNormalize(vec);
+ self.move_origin[1] = vec[1];
+
+ self.move_origin[2] = self.s.origin[2] - self.target_ent.s.origin[2];
+
+ // add the driver to the end of them team chain
+ for (ent = self.target_ent.teammaster; ent.teamchain != null; ent = ent.teamchain);
+ ent.teamchain = self;
+ self.teammaster = self.target_ent.teammaster;
+ self.flags |= FL_TEAMSLAVE;
+ return true;
+ }
+ };
+
+ public static void SP_turret_driver(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ self.movetype = MOVETYPE_PUSH;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
+ VectorSet(self.mins, -16, -16, -24);
+ VectorSet(self.maxs, 16, 16, 32);
+
+ self.health = 100;
+ self.gib_health = 0;
+ self.mass = 200;
+ self.viewheight = 24;
+
+ self.die = turret_driver_die;
+ self.monsterinfo.stand = M_Infantry.infantry_stand;
+
+ self.flags |= FL_NO_KNOCKBACK;
+
+ level.total_monsters++;
+
+ self.svflags |= SVF_MONSTER;
+ self.s.renderfx |= RF_FRAMELERP;
+ self.takedamage = DAMAGE_AIM;
+ self.use = monster_use;
+ self.clipmask = MASK_MONSTERSOLID;
+ VectorCopy(self.s.origin, self.s.old_origin);
+ self.monsterinfo.aiflags |= AI_STAND_GROUND | AI_DUCKED;
+
+ if (st.item != null) {
+ self.item = FindItemByClassname(st.item);
+ if (self.item == null)
+ gi.dprintf(self.classname + " at " + vtos(self.s.origin) + " has bad item: " + st.item + "\n");
+ }
+
+ self.think = turret_driver_link;
+ self.nextthink = level.time + FRAMETIME;
+
+ gi.linkentity(self);
+ }
+}
diff --git a/src/jake2/game/GameUtil.java b/src/jake2/game/GameUtil.java
new file mode 100644
index 0000000..e959106
--- /dev/null
+++ b/src/jake2/game/GameUtil.java
@@ -0,0 +1,1840 @@
+/*
+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 01.11.2003 by RST.
+// $Id: GameUtil.java,v 1.1 2004-07-07 19:59:05 hzi Exp $
+
+package jake2.game;
+
+import java.sql.Savepoint;
+
+import jake2.Defines;
+import jake2.client.M;
+import jake2.qcommon.Com;
+import jake2.util.*;
+
+public class GameUtil extends GameBase {
+
+ public static EntThinkAdapter Think_Delay = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ G_UseTargets(ent, ent.activator);
+ G_FreeEdict(ent);
+ return true;
+ }
+ };
+
+ public static void checkClassname(edict_t ent)
+ {
+
+ if (ent.classname ==null)
+ {
+ Com.Printf("edict with classname = null: " + ent.index);
+ }
+ }
+
+ /**
+ the global "activator" should be set to the entity that initiated the firing.
+
+ If self.delay is set, a DelayedUse entity will be created that will actually
+ do the SUB_UseTargets after that many seconds have passed.
+
+ Centerprints any self.message to the activator.
+
+ Search for (string)targetname in all entities that
+ match (string)self.target and call their .use function
+ */
+
+ public static void G_UseTargets(edict_t ent, edict_t activator) {
+ edict_t t;
+
+ checkClassname(ent);
+
+
+ //
+ // check for a delay
+ //
+ if (ent.delay != 0) {
+ // create a temp object to fire at a later time
+ t = G_Spawn();
+ t.classname = "DelayedUse";
+ t.nextthink = level.time + ent.delay;
+ t.think = Think_Delay;
+ t.activator = activator;
+ if (activator == null)
+ gi.dprintf("Think_Delay with no activator\n");
+ t.message = ent.message;
+ t.target = ent.target;
+ t.killtarget = ent.killtarget;
+ return;
+ }
+
+ //
+ // print the message
+ //
+ if ((ent.message != null) && (activator.svflags & SVF_MONSTER) == 0) {
+ gi.centerprintf(activator, "" + ent.message);
+ if (ent.noise_index != 0)
+ gi.sound(activator, CHAN_AUTO, ent.noise_index, 1, ATTN_NORM, 0);
+ else
+ gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
+ }
+
+ //
+ // kill killtargets
+ //
+
+ EdictIterator edit = null;
+
+ if (ent.killtarget != null) {
+ while ((edit = G_Find(edit, findByTarget, ent.killtarget)) != null) {
+ t = edit.o;
+ G_FreeEdict(t);
+ if (!ent.inuse) {
+ gi.dprintf("entity was removed while using killtargets\n");
+ return;
+ }
+ }
+ }
+
+ // fire targets
+
+ if (ent.target != null) {
+ edit = null;
+ while ((edit = G_Find(edit, findByTarget, ent.target)) != null) {
+ t = edit.o;
+ // doors fire area portals in a specific way
+ if (Lib.Q_stricmp("func_areaportal", t.classname) == 0
+ && (Lib.Q_stricmp("func_door", ent.classname) == 0 || Lib.Q_stricmp("func_door_rotating", ent.classname) == 0))
+ continue;
+
+ if (t == ent) {
+ gi.dprintf("WARNING: Entity used itself.\n");
+ }
+ else {
+ if (t.use != null)
+ t.use.use(t, ent, activator);
+ }
+ if (!ent.inuse) {
+ gi.dprintf("entity was removed while using targets\n");
+ return;
+ }
+ }
+ }
+ }
+
+ public static void G_InitEdict(edict_t e, int i) {
+ e.inuse = true;
+ e.classname = "noclass";
+ e.gravity = 1.0f;
+ //e.s.number= e - g_edicts;�
+ e.s.number= i;
+ e.index = i;
+ }
+
+ /**
+ * Either finds a free edict, or allocates a new one.
+ * Try to avoid reusing an entity that was recently freed, because it
+ * can cause the client to think the entity morphed into something else
+ * instead of being removed and recreated, which can cause interpolated
+ * angles and bad trails.
+ */
+ public static edict_t G_Spawn() {
+ int i;
+ edict_t e = null;
+
+ for (i = (int) maxclients.value + 1; i < globals.num_edicts; i++) {
+ e = g_edicts[i];
+ // the first couple seconds of server time can involve a lot of
+ // freeing and allocating, so relax the replacement policy
+ if (!e.inuse && (e.freetime < 2 || level.time - e.freetime > 0.5)) {
+ G_InitEdict(e, i);
+ return e;
+ }
+ }
+
+ if (i == game.maxentities)
+ gi.error("ED_Alloc: no free edicts");
+
+ e = g_edicts[i];
+ globals.num_edicts++;
+ G_InitEdict(e, i);
+ return e;
+ }
+
+ public static EntThinkAdapter G_FreeEdictA = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ G_FreeEdict(ent);
+ return false;
+ }
+ };
+
+ /**
+ * Marks the edict as free
+ */
+ public static void G_FreeEdict(edict_t ed) {
+ gi.unlinkentity(ed); // unlink from world
+
+ //if ((ed - g_edicts) <= (maxclients.value + BODY_QUEUE_SIZE))
+ if (ed.index <= (maxclients.value + BODY_QUEUE_SIZE)) {
+ // gi.dprintf("tried to free special edict\n");
+ return;
+ }
+
+ //memset(ed, 0, sizeof(* ed));
+ ed.clear();
+ ed.classname = "freed";
+ ed.freetime = level.time;
+ ed.inuse = false;
+ }
+
+ /**
+ * Call after linking a new trigger in during gameplay
+ * to force all entities it covers to immediately touch it.
+ */
+
+ public static void G_TouchSolids(edict_t ent) {
+ int i, num;
+ edict_t touch[] = new edict_t[MAX_EDICTS], hit;
+
+ num = gi.BoxEdicts(ent.absmin, ent.absmax, touch, MAX_EDICTS, AREA_SOLID);
+
+ // be careful, it is possible to have an entity in this
+ // list removed before we get to it (killtriggered)
+ for (i = 0; i < num; i++) {
+ hit = touch[i];
+ if (!hit.inuse)
+ continue;
+ if (ent.touch != null)
+ ent.touch.touch(hit, ent, null, null);
+ if (!ent.inuse)
+ break;
+ }
+ }
+
+ /**
+ * Kills all entities that would touch the proposed new positioning
+ * of ent. Ent should be unlinked before calling this!
+ */
+
+ public static boolean KillBox(edict_t ent) {
+ trace_t tr;
+
+ while (true) {
+ tr = gi.trace(ent.s.origin, ent.mins, ent.maxs, ent.s.origin, null, MASK_PLAYERSOLID);
+ if (tr.ent == null || tr.ent == g_edicts[0])
+ break;
+
+ // nail it
+ T_Damage(tr.ent, ent, ent, vec3_origin, ent.s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
+
+ // if we didn't kill it, fail
+ if (tr.ent.solid != 0)
+ return false;
+ }
+
+ return true; // all clear
+ }
+
+ public static boolean OnSameTeam(edict_t ent1, edict_t ent2) {
+ if (0 == ((int) (dmflags.value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
+ return false;
+
+ if (ClientTeam(ent1).equals(ClientTeam(ent2)))
+ return true;
+ return false;
+ }
+
+ /** TODO: test, / replaced the string operations. */
+ static String ClientTeam(edict_t ent) {
+ String value;
+
+ if (ent.client == null)
+ return "";
+
+ value = Info.Info_ValueForKey(ent.client.pers.userinfo, "skin");
+
+ int p = value.indexOf("/");
+
+ if (p == -1)
+ return value;
+
+ if (((int) (dmflags.value) & DF_MODELTEAMS) != 0) {
+ return value.substring(0, p);
+ }
+
+ return value.substring(p + 1, value.length());
+ }
+
+ static EntThinkAdapter MegaHealth_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.owner.health > self.owner.max_health) {
+ self.nextthink = level.time + 1;
+ self.owner.health -= 1;
+ return false;
+ }
+
+ if (!((self.spawnflags & DROPPED_ITEM) != 0) && (deathmatch.value != 0))
+ SetRespawn(self, 20);
+ else
+ G_FreeEdict(self);
+
+ return false;
+ }
+ };
+
+ static EntThinkAdapter DoRespawn = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ if (ent.team != null) {
+ edict_t master;
+ int count;
+ int choice = 0;
+
+ master = ent.teammaster;
+
+ // tiefe z�hlen
+ // count the depth
+ for (count = 0, ent = master; ent != null; ent = ent.chain, count++);
+
+ choice = Lib.rand() % count;
+
+ for (count = 0, ent = master; count < choice; ent = ent.chain, count++);
+ }
+
+ ent.svflags &= ~SVF_NOCLIENT;
+ ent.solid = SOLID_TRIGGER;
+ gi.linkentity(ent);
+
+ // send an effect
+ ent.s.event = EV_ITEM_RESPAWN;
+
+ return false;
+ }
+ };
+
+ static void SetRespawn(edict_t ent, float delay) {
+ ent.flags |= FL_RESPAWN;
+ ent.svflags |= SVF_NOCLIENT;
+ ent.solid = SOLID_NOT;
+ ent.nextthink = level.time + delay;
+ ent.think = DoRespawn;
+ gi.linkentity(ent);
+ }
+
+ static EntInteractAdapter Pickup_Pack = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+
+ gitem_t item;
+ int index;
+
+ if (other.client.pers.max_bullets < 300)
+ other.client.pers.max_bullets = 300;
+ if (other.client.pers.max_shells < 200)
+ other.client.pers.max_shells = 200;
+ if (other.client.pers.max_rockets < 100)
+ other.client.pers.max_rockets = 100;
+ if (other.client.pers.max_grenades < 100)
+ other.client.pers.max_grenades = 100;
+ if (other.client.pers.max_cells < 300)
+ other.client.pers.max_cells = 300;
+ if (other.client.pers.max_slugs < 100)
+ other.client.pers.max_slugs = 100;
+
+ item = FindItem("Bullets");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_bullets)
+ other.client.pers.inventory[index] = other.client.pers.max_bullets;
+ }
+
+ item = FindItem("Shells");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_shells)
+ other.client.pers.inventory[index] = other.client.pers.max_shells;
+ }
+
+ item = FindItem("Cells");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_cells)
+ other.client.pers.inventory[index] = other.client.pers.max_cells;
+ }
+
+ item = FindItem("Grenades");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_grenades)
+ other.client.pers.inventory[index] = other.client.pers.max_grenades;
+ }
+
+ item = FindItem("Rockets");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_rockets)
+ other.client.pers.inventory[index] = other.client.pers.max_rockets;
+ }
+
+ item = FindItem("Slugs");
+ if (item != null) {
+ index = ITEM_INDEX(item);
+ other.client.pers.inventory[index] += item.quantity;
+ if (other.client.pers.inventory[index] > other.client.pers.max_slugs)
+ other.client.pers.inventory[index] = other.client.pers.max_slugs;
+ }
+
+ if (0 == (ent.spawnflags & DROPPED_ITEM) && (deathmatch.value != 0))
+ SetRespawn(ent, ent.item.quantity);
+
+ return true;
+ }
+ };
+
+ final static EntInteractAdapter Pickup_Health = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+
+ if (0 == (ent.style & HEALTH_IGNORE_MAX))
+ if (other.health >= other.max_health)
+ return false;
+
+ other.health += ent.count;
+
+ if (0 == (ent.style & HEALTH_IGNORE_MAX)) {
+ if (other.health > other.max_health)
+ other.health = other.max_health;
+ }
+
+ if (0 != (ent.style & HEALTH_TIMED)) {
+ ent.think = MegaHealth_think;
+ ent.nextthink = level.time + 5f;
+ ent.owner = other;
+ ent.flags |= FL_RESPAWN;
+ ent.svflags |= SVF_NOCLIENT;
+ ent.solid = SOLID_NOT;
+ }
+ else {
+ if (!((ent.spawnflags & DROPPED_ITEM) != 0) && (deathmatch.value != 0))
+ SetRespawn(ent, 30);
+ }
+
+ return true;
+ }
+
+ };
+
+ static int ITEM_INDEX(gitem_t item) {
+ return item.index;
+ }
+
+ /*
+ ===============
+ Touch_Item
+ ===============
+ */
+
+ static EntTouchAdapter Touch_Item = new EntTouchAdapter() {
+ public void touch(edict_t ent, edict_t other, cplane_t plane, csurface_t surf) {
+ boolean taken;
+
+ if (other.client == null)
+ return;
+ if (other.health < 1)
+ return; // dead people can't pickup
+ if (ent.item.pickup == null)
+ return; // not a grabbable item?
+
+ taken = ent.item.pickup.interact(ent, other);
+
+ if (taken) {
+ // flash the screen
+ other.client.bonus_alpha = 0.25f;
+
+ // show icon and name on status bar
+ other.client.ps.stats[STAT_PICKUP_ICON] = (short) gi.imageindex(ent.item.icon);
+ other.client.ps.stats[STAT_PICKUP_STRING] = (short) (CS_ITEMS + ITEM_INDEX(ent.item));
+ other.client.pickup_msg_time = level.time + 3.0f;
+
+ // change selected item
+ if (ent.item.use != null)
+ other.client.pers.selected_item = other.client.ps.stats[STAT_SELECTED_ITEM] = (short) ITEM_INDEX(ent.item);
+
+ if (ent.item.pickup == Pickup_Health) {
+ if (ent.count == 2)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/s_health.wav"), 1, ATTN_NORM, 0);
+ else if (ent.count == 10)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/n_health.wav"), 1, ATTN_NORM, 0);
+ else if (ent.count == 25)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/l_health.wav"), 1, ATTN_NORM, 0);
+ else // (ent.count == 100)
+ gi.sound(other, CHAN_ITEM, gi.soundindex("items/m_health.wav"), 1, ATTN_NORM, 0);
+ }
+ else if (ent.item.pickup_sound != null) {
+ gi.sound(other, CHAN_ITEM, gi.soundindex(ent.item.pickup_sound), 1, ATTN_NORM, 0);
+ }
+ }
+
+ if (0 == (ent.spawnflags & ITEM_TARGETS_USED)) {
+ G_UseTargets(ent, other);
+ ent.spawnflags |= ITEM_TARGETS_USED;
+ }
+
+ if (!taken)
+ return;
+
+ if (!((coop.value != 0) && (ent.item.flags & IT_STAY_COOP) != 0)
+ || 0 != (ent.spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM))) {
+ if ((ent.flags & FL_RESPAWN) != 0)
+ ent.flags &= ~FL_RESPAWN;
+ else
+ G_FreeEdict(ent);
+ }
+ }
+ };
+
+ static EntTouchAdapter drop_temp_touch = new EntTouchAdapter() {
+ public void touch(edict_t ent, edict_t other, cplane_t plane, csurface_t surf) {
+ if (other == ent.owner)
+ return;
+
+ Touch_Item.touch(ent, other, plane, surf);
+ }
+ };
+
+ static EntThinkAdapter drop_make_touchable = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ ent.touch = Touch_Item;
+ if (deathmatch.value != 0) {
+ ent.nextthink = level.time + 29;
+ ent.think = G_FreeEdictA;
+ }
+ return false;
+ }
+ };
+
+ static edict_t Drop_Item(edict_t ent, gitem_t item) {
+ edict_t dropped;
+ float[] forward = { 0, 0, 0 };
+ float[] right = { 0, 0, 0 };
+ float[] offset = { 0, 0, 0 };
+
+ dropped = G_Spawn();
+
+ dropped.classname = item.classname;
+ dropped.item = item;
+ dropped.spawnflags = DROPPED_ITEM;
+ dropped.s.effects = item.world_model_flags;
+ dropped.s.renderfx = RF_GLOW;
+ Math3D.VectorSet(dropped.mins, -15, -15, -15);
+ Math3D.VectorSet(dropped.maxs, 15, 15, 15);
+ gi.setmodel(dropped, dropped.item.world_model);
+ dropped.solid = SOLID_TRIGGER;
+ dropped.movetype = MOVETYPE_TOSS;
+
+ dropped.touch = drop_temp_touch;
+
+ dropped.owner = ent;
+
+ if (ent.client != null) {
+ trace_t trace;
+
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, null);
+ Math3D.VectorSet(offset, 24, 0, -16);
+ Math3D.G_ProjectSource(ent.s.origin, offset, forward, right, dropped.s.origin);
+ trace = gi.trace(ent.s.origin, dropped.mins, dropped.maxs, dropped.s.origin, ent, CONTENTS_SOLID);
+ Math3D.VectorCopy(trace.endpos, dropped.s.origin);
+ }
+ else {
+ Math3D.AngleVectors(ent.s.angles, forward, right, null);
+ Math3D.VectorCopy(ent.s.origin, dropped.s.origin);
+ }
+
+ Math3D.VectorScale(forward, 100, dropped.velocity);
+ dropped.velocity[2] = 300;
+
+ dropped.think = drop_make_touchable;
+ dropped.nextthink = level.time + 1;
+
+ gi.linkentity(dropped);
+
+ return dropped;
+ }
+
+ static void ValidateSelectedItem(edict_t ent) {
+ gclient_t cl;
+
+ cl = ent.client;
+
+ if (cl.pers.inventory[cl.pers.selected_item] != 0)
+ return; // valid
+
+ GameAI.SelectNextItem(ent, -1);
+ }
+
+ static int quad_drop_timeout_hack = 0;
+
+ static ItemUseAdapter Use_Quad = new ItemUseAdapter() {
+
+ public void use(edict_t ent, gitem_t item) {
+ int timeout;
+
+ ent.client.pers.inventory[ITEM_INDEX(item)]--;
+ ValidateSelectedItem(ent);
+
+ if (quad_drop_timeout_hack != 0) {
+ timeout = quad_drop_timeout_hack;
+ quad_drop_timeout_hack = 0;
+ }
+ else {
+ timeout = 300;
+ }
+
+ if (ent.client.quad_framenum > level.framenum)
+ ent.client.quad_framenum += timeout;
+ else
+ ent.client.quad_framenum = level.framenum + timeout;
+
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+
+ static ItemUseAdapter Use_Invulnerability = new ItemUseAdapter() {
+ public void use(edict_t ent, gitem_t item) {
+ ent.client.pers.inventory[ITEM_INDEX(item)]--;
+ ValidateSelectedItem(ent);
+
+ if (ent.client.invincible_framenum > level.framenum)
+ ent.client.invincible_framenum += 300;
+ else
+ ent.client.invincible_framenum = level.framenum + 300;
+
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+
+ static void Use_Item(edict_t ent, edict_t other, edict_t activator) {
+ ent.svflags &= ~SVF_NOCLIENT;
+ ent.use = null;
+
+ if ((ent.spawnflags & ITEM_NO_TOUCH) != 0) {
+ ent.solid = SOLID_BBOX;
+ ent.touch = null;
+ }
+ else {
+ ent.solid = SOLID_TRIGGER;
+ ent.touch = Touch_Item;
+ }
+
+ gi.linkentity(ent);
+ }
+
+ // ======================================================================
+
+ static ItemUseAdapter Use_Breather = new ItemUseAdapter() {
+ public void use(edict_t ent, gitem_t item) {
+ ent.client.pers.inventory[ITEM_INDEX(item)]--;
+ ValidateSelectedItem(ent);
+
+ if (ent.client.breather_framenum > level.framenum)
+ ent.client.breather_framenum += 300;
+ else
+ ent.client.breather_framenum = level.framenum + 300;
+
+ // gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+
+ // ======================================================================
+
+ static ItemUseAdapter Use_Envirosuit = new ItemUseAdapter() {
+ public void use(edict_t ent, gitem_t item) {
+ ent.client.pers.inventory[ITEM_INDEX(item)]--;
+ ValidateSelectedItem(ent);
+
+ if (ent.client.enviro_framenum > level.framenum)
+ ent.client.enviro_framenum += 300;
+ else
+ ent.client.enviro_framenum = level.framenum + 300;
+
+ // gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+
+ // ======================================================================
+ /*
+ static ItemUseAdapter Use_Invulnerability = new ItemUseAdapter()
+ {
+ public void use(edict_t ent, gitem_t item)
+ {
+
+ ent.client.pers.inventory[ITEM_INDEX(item)]--;
+ ValidateSelectedItem(ent);
+
+ if (ent.client.invincible_framenum > level.framenum)
+ ent.client.invincible_framenum += 300;
+ else
+ ent.client.invincible_framenum = level.framenum + 300;
+
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+ */
+
+ // ======================================================================
+
+ static ItemUseAdapter Use_Silencer = new ItemUseAdapter() {
+ public void use(edict_t ent, gitem_t item) {
+
+ ent.client.pers.inventory[ITEM_INDEX(item)]--;
+ ValidateSelectedItem(ent);
+ ent.client.silencer_shots += 30;
+
+ // gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
+ }
+ };
+
+ // ======================================================================
+
+ static EntInteractAdapter Pickup_Key = new EntInteractAdapter() {
+ public boolean interact(edict_t ent, edict_t other) {
+ if (coop.value != 0) {
+ if (Lib.strcmp(ent.classname, "key_power_cube") == 0) {
+ if ((other.client.pers.power_cubes & ((ent.spawnflags & 0x0000ff00) >> 8)) != 0)
+ return false;
+ other.client.pers.inventory[ITEM_INDEX(ent.item)]++;
+ other.client.pers.power_cubes |= ((ent.spawnflags & 0x0000ff00) >> 8);
+ }
+ else {
+ if (other.client.pers.inventory[ITEM_INDEX(ent.item)] != 0)
+ return false;
+ other.client.pers.inventory[ITEM_INDEX(ent.item)] = 1;
+ }
+ return true;
+ }
+ other.client.pers.inventory[ITEM_INDEX(ent.item)]++;
+ return true;
+ }
+ };
+
+ /*
+ ============
+ CanDamage
+
+ Returns true if the inflictor can directly damage the target. Used for
+ explosions and melee attacks.
+ ============
+ */
+ static boolean CanDamage(edict_t targ, edict_t inflictor) {
+ float[] dest = { 0, 0, 0 };
+ trace_t trace;
+
+ // bmodels need special checking because their origin is 0,0,0
+ if (targ.movetype == MOVETYPE_PUSH) {
+ Math3D.VectorAdd(targ.absmin, targ.absmax, dest);
+ Math3D.VectorScale(dest, 0.5f, dest);
+ trace = gi.trace(inflictor.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+ if (trace.fraction == 1.0f)
+ return true;
+ if (trace.ent == targ)
+ return true;
+ return false;
+ }
+
+ trace = gi.trace(inflictor.s.origin, vec3_origin, vec3_origin, targ.s.origin, inflictor, MASK_SOLID);
+ if (trace.fraction == 1.0)
+ return true;
+
+ Math3D.VectorCopy(targ.s.origin, dest);
+ dest[0] += 15.0;
+ dest[1] += 15.0;
+ trace = gi.trace(inflictor.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+ if (trace.fraction == 1.0)
+ return true;
+
+ Math3D.VectorCopy(targ.s.origin, dest);
+ dest[0] += 15.0;
+ dest[1] -= 15.0;
+ trace = gi.trace(inflictor.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+ if (trace.fraction == 1.0)
+ return true;
+
+ Math3D.VectorCopy(targ.s.origin, dest);
+ dest[0] -= 15.0;
+ dest[1] += 15.0;
+ trace = gi.trace(inflictor.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+ if (trace.fraction == 1.0)
+ return true;
+
+ Math3D.VectorCopy(targ.s.origin, dest);
+ dest[0] -= 15.0;
+ dest[1] -= 15.0;
+ trace = gi.trace(inflictor.s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
+ if (trace.fraction == 1.0)
+ return true;
+
+ return false;
+ }
+
+ public static void T_Damage(
+ edict_t targ,
+ edict_t inflictor,
+ edict_t attacker,
+ float[] dir,
+ float[] point,
+ float[] normal,
+ int damage,
+ int knockback,
+ int dflags,
+ int mod) {
+ gclient_t client;
+ int take;
+ int save;
+ int asave;
+ int psave;
+ int te_sparks;
+
+ if (targ.takedamage != 0)
+ return;
+
+ // friendly fire avoidance
+ // if enabled you can't hurt teammates (but you can hurt yourself)
+ // knockback still occurs
+ if ((targ != attacker)
+ && ((deathmatch.value != 0 && 0 != ((int) (dmflags.value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop.value != 0)) {
+ if (OnSameTeam(targ, attacker)) {
+ if (((int) (dmflags.value) & DF_NO_FRIENDLY_FIRE) != 0)
+ damage = 0;
+ else
+ mod |= MOD_FRIENDLY_FIRE;
+ }
+ }
+ meansOfDeath = mod;
+
+ // easy mode takes half damage
+ if (skill.value == 0 && deathmatch.value == 0 && targ.client != null) {
+ damage *= 0.5;
+ if (damage == 0)
+ damage = 1;
+ }
+
+ client = targ.client;
+
+ if ((dflags & DAMAGE_BULLET) != 0)
+ te_sparks = TE_BULLET_SPARKS;
+ else
+ te_sparks = TE_SPARKS;
+
+ Math3D.VectorNormalize(dir);
+
+ // bonus damage for suprising a monster
+ if (0 == (dflags & DAMAGE_RADIUS)
+ && (targ.svflags & SVF_MONSTER) != 0
+ && (attacker.client != null)
+ && (targ.enemy == null)
+ && (targ.health > 0))
+ damage *= 2;
+
+ if ((targ.flags & FL_NO_KNOCKBACK) != 0)
+ knockback = 0;
+
+ // figure momentum add
+ if (0 == (dflags & DAMAGE_NO_KNOCKBACK)) {
+ if ((knockback != 0)
+ && (targ.movetype != MOVETYPE_NONE)
+ && (targ.movetype != MOVETYPE_BOUNCE)
+ && (targ.movetype != MOVETYPE_PUSH)
+ && (targ.movetype != MOVETYPE_STOP)) {
+ float[] kvel = { 0, 0, 0 };
+ float mass;
+
+ if (targ.mass < 50)
+ mass = 50;
+ else
+ mass = targ.mass;
+
+ if (targ.client != null && attacker == targ)
+ Math3D.VectorScale(dir, 1600.0f * (float) knockback / mass, kvel);
+ // the rocket jump hack...
+ else
+ Math3D.VectorScale(dir, 500.0f * (float) knockback / mass, kvel);
+
+ Math3D.VectorAdd(targ.velocity, kvel, targ.velocity);
+ }
+ }
+
+ take = damage;
+ save = 0;
+
+ // check for godmode
+ if ((targ.flags & FL_GODMODE) != 0 && 0 == (dflags & DAMAGE_NO_PROTECTION)) {
+ take = 0;
+ save = damage;
+ SpawnDamage(te_sparks, point, normal, save);
+ }
+
+ // check for invincibility
+ if ((client != null && client.invincible_framenum > level.framenum) && 0 == (dflags & DAMAGE_NO_PROTECTION)) {
+ if (targ.pain_debounce_time < level.time) {
+ gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
+ targ.pain_debounce_time = level.time + 2;
+ }
+ take = 0;
+ save = damage;
+ }
+
+ psave = CheckPowerArmor(targ, point, normal, take, dflags);
+ take -= psave;
+
+ asave = CheckArmor(targ, point, normal, take, te_sparks, dflags);
+ take -= asave;
+
+ // treat cheat/powerup savings the same as armor
+ asave += save;
+
+ // team damage avoidance
+ if (0 == (dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage(targ, attacker))
+ return;
+
+ // do the damage
+ if (take != 0) {
+ if (0 != (targ.svflags & SVF_MONSTER) || (client != null))
+ SpawnDamage(TE_BLOOD, point, normal, take);
+ else
+ SpawnDamage(te_sparks, point, normal, take);
+
+ targ.health = targ.health - take;
+
+ if (targ.health <= 0) {
+ if ((targ.svflags & SVF_MONSTER) != 0 || (client != null))
+ targ.flags |= FL_NO_KNOCKBACK;
+ Killed(targ, inflictor, attacker, take, point);
+ return;
+ }
+ }
+
+ if ((targ.svflags & SVF_MONSTER) != 0) {
+ M.M_ReactToDamage(targ, attacker);
+ if (0 != (targ.monsterinfo.aiflags & AI_DUCKED) && (take != 0)) {
+ targ.pain.pain(targ, attacker, knockback, take);
+ // nightmare mode monsters don't go into pain frames often
+ if (skill.value == 3)
+ targ.pain_debounce_time = level.time + 5;
+ }
+ }
+ else if (client != null) {
+ if (((targ.flags & FL_GODMODE) == 0) && (take != 0))
+ targ.pain.pain(targ, attacker, knockback, take);
+ }
+ else if (take != 0) {
+ if (targ.pain != null)
+ targ.pain.pain(targ, attacker, knockback, take);
+ }
+
+ // add to the damage inflicted on a player this frame
+ // the total will be turned into screen blends and view angle kicks
+ // at the end of the frame
+ if (client != null) {
+ client.damage_parmor += psave;
+ client.damage_armor += asave;
+ client.damage_blood += take;
+ client.damage_knockback += knockback;
+ Math3D.VectorCopy(point, client.damage_from);
+ }
+ }
+
+ /*
+ ============
+ Killed
+ ============
+ */
+ public static void Killed(edict_t targ, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ if (targ.health < -999)
+ targ.health = -999;
+
+ Com.Println("Killed:" + targ.classname);
+ targ.enemy = attacker;
+
+ if ((targ.svflags & SVF_MONSTER) != 0 && (targ.deadflag != DEAD_DEAD)) {
+ // targ.svflags |= SVF_DEADMONSTER; // now treat as a different content type
+ if (0 == (targ.monsterinfo.aiflags & AI_GOOD_GUY)) {
+ level.killed_monsters++;
+ if (!(coop.value != 0 && attacker.client != null))
+ attacker.client.resp.score++;
+ // medics won't heal monsters that they kill themselves
+ if (attacker.classname.equals("monster_medic"))
+ targ.owner = attacker;
+ }
+ }
+
+ if (targ.movetype == MOVETYPE_PUSH
+ || targ.movetype == MOVETYPE_STOP
+ || targ.movetype == MOVETYPE_NONE) { // doors, triggers, etc
+ targ.die.die(targ, inflictor, attacker, damage, point);
+ return;
+ }
+
+ if ((targ.svflags & SVF_MONSTER) != 0 && (targ.deadflag != DEAD_DEAD)) {
+ targ.touch = null;
+ Monster.monster_death_use(targ);
+ }
+
+ targ.die.die(targ, inflictor, attacker, damage, point);
+ }
+
+ /*
+ ================
+ SpawnDamage
+ ================
+ */
+ static void SpawnDamage(int type, float[] origin, float[] normal, int damage) {
+ if (damage > 255)
+ damage = 255;
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(type);
+ // gi.WriteByte (damage);
+ gi.WritePosition(origin);
+ gi.WriteDir(normal);
+ gi.multicast(origin, MULTICAST_PVS);
+ }
+
+ static int PowerArmorType(edict_t ent) {
+ if (ent.client == null)
+ return POWER_ARMOR_NONE;
+
+ if (0 == (ent.flags & FL_POWER_ARMOR))
+ return POWER_ARMOR_NONE;
+
+ if (ent.client.pers.inventory[power_shield_index] > 0)
+ return POWER_ARMOR_SHIELD;
+
+ if (ent.client.pers.inventory[power_screen_index] > 0)
+ return POWER_ARMOR_SCREEN;
+
+ return POWER_ARMOR_NONE;
+ }
+
+ static int jacket_armor_index;
+ static int combat_armor_index;
+ static int body_armor_index;
+ static int power_screen_index;
+ static int power_shield_index;
+
+ static int CheckPowerArmor(edict_t ent, float[] point, float[] normal, int damage, int dflags) {
+ gclient_t client;
+ int save;
+ int power_armor_type;
+ int index = 0;
+ int damagePerCell;
+ int pa_te_type;
+ int power = 0;
+ int power_used;
+
+ if (damage != 0)
+ return 0;
+
+ client = ent.client;
+
+ if ((dflags & DAMAGE_NO_ARMOR) != 0)
+ return 0;
+
+ if (client != null) {
+ power_armor_type = PowerArmorType(ent);
+ if (power_armor_type != POWER_ARMOR_NONE) {
+ index = ITEM_INDEX(FindItem("Cells"));
+ power = client.pers.inventory[index];
+ }
+ }
+ else if ((ent.svflags & SVF_MONSTER) != 0) {
+ power_armor_type = ent.monsterinfo.power_armor_type;
+ power = ent.monsterinfo.power_armor_power;
+ }
+ else
+ return 0;
+
+ if (power_armor_type == POWER_ARMOR_NONE)
+ return 0;
+ if (power == 0)
+ return 0;
+
+ if (power_armor_type == POWER_ARMOR_SCREEN) {
+ float[] vec = { 0, 0, 0 };
+ float dot;
+ float[] forward = { 0, 0, 0 };
+
+ // only works if damage point is in front
+ Math3D.AngleVectors(ent.s.angles, forward, null, null);
+ Math3D.VectorSubtract(point, ent.s.origin, vec);
+ Math3D.VectorNormalize(vec);
+ dot = Math3D.DotProduct(vec, forward);
+ if (dot <= 0.3)
+ return 0;
+
+ damagePerCell = 1;
+ pa_te_type = TE_SCREEN_SPARKS;
+ damage = damage / 3;
+ }
+ else {
+ damagePerCell = 2;
+ pa_te_type = TE_SHIELD_SPARKS;
+ damage = (2 * damage) / 3;
+ }
+
+ save = power * damagePerCell;
+
+ if (save == 0)
+ return 0;
+ if (save > damage)
+ save = damage;
+
+ SpawnDamage(pa_te_type, point, normal, save);
+ ent.powerarmor_time = level.time + 0.2f;
+
+ power_used = save / damagePerCell;
+
+ if (client != null)
+ client.pers.inventory[index] -= power_used;
+ else
+ ent.monsterinfo.power_armor_power -= power_used;
+ return save;
+ }
+
+ /**
+ * The monster is walking it's beat.
+ *
+ */
+ static void ai_walk(edict_t self, float dist) {
+ M.M_MoveToGoal(self, dist);
+
+ // check for noticing a player
+ if (FindTarget(self))
+ return;
+
+ if ((self.monsterinfo.search != null) && (level.time > self.monsterinfo.idle_time)) {
+ if (self.monsterinfo.idle_time != 0) {
+ self.monsterinfo.search.think(self);
+ self.monsterinfo.idle_time = level.time + 15 + Lib.random() * 15;
+ }
+ else {
+ self.monsterinfo.idle_time = level.time + Lib.random() * 15;
+ }
+ }
+ }
+
+ /*
+ =============
+ range
+
+ returns the range catagorization of an entity reletive to self.
+ 0 melee range, will become hostile even if back is turned
+ 1 visibility and infront, or visibility and show hostile
+ 2 infront and show hostile
+ 3 only triggered by damage
+
+ */
+ // static int range(edict_t self, edict_t other)
+ // {
+ // float[] v= { 0, 0, 0 };
+ // float len;
+ //
+ // VectorSubtract(self.s.origin, other.s.origin, v);
+ // len= VectorLength(v);
+ // if (len < MELEE_DISTANCE)
+ // return RANGE_MELEE;
+ // if (len < 500)
+ // return RANGE_NEAR;
+ // if (len < 1000)
+ // return RANGE_MID;
+ // return RANGE_FAR;
+ // }
+
+ // ============================================================================
+
+ static EntThinkAdapter M_CheckAttack = new EntThinkAdapter() {
+
+ public boolean think(edict_t self) {
+ float[] spot1 = { 0, 0, 0 };
+
+ float[] spot2 = { 0, 0, 0 };
+ float chance;
+ trace_t tr;
+
+ if (self.enemy.health > 0) {
+ // see if any entities are in the way of the shot
+ Math3D.VectorCopy(self.s.origin, spot1);
+ spot1[2] += self.viewheight;
+ Math3D.VectorCopy(self.enemy.s.origin, spot2);
+ spot2[2] += self.enemy.viewheight;
+
+ tr =
+ gi.trace(
+ spot1,
+ null,
+ null,
+ spot2,
+ self,
+ CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA | CONTENTS_WINDOW);
+
+ // do we have a clear shot?
+ if (tr.ent != self.enemy)
+ return false;
+ }
+
+ // melee attack
+ if (enemy_range == RANGE_MELEE) {
+ // don't always melee in easy mode
+ if (skill.value == 0 && (Lib.rand() & 3) != 0)
+ return false;
+ if (self.monsterinfo.melee != null)
+ self.monsterinfo.attack_state = AS_MELEE;
+ else
+ self.monsterinfo.attack_state = AS_MISSILE;
+ return true;
+ }
+
+ // missile attack
+ if (self.monsterinfo.attack == null)
+ return false;
+
+ if (level.time < self.monsterinfo.attack_finished)
+ return false;
+
+ if (enemy_range == RANGE_FAR)
+ return false;
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ chance = 0.4f;
+ }
+ else if (enemy_range == RANGE_MELEE) {
+ chance = 0.2f;
+ }
+ else if (enemy_range == RANGE_NEAR) {
+ chance = 0.1f;
+ }
+ else if (enemy_range == RANGE_MID) {
+ chance = 0.02f;
+ }
+ else {
+ return false;
+ }
+
+ if (skill.value == 0)
+ chance *= 0.5;
+ else if (skill.value >= 2)
+ chance *= 2;
+
+ if (Lib.random() < chance) {
+ self.monsterinfo.attack_state = AS_MISSILE;
+ self.monsterinfo.attack_finished = level.time + 2 * Lib.random();
+ return true;
+ }
+
+ if ((self.flags & FL_FLY) != 0) {
+ if (Lib.random() < 0.3f)
+ self.monsterinfo.attack_state = AS_SLIDING;
+ else
+ self.monsterinfo.attack_state = AS_STRAIGHT;
+ }
+
+ return false;
+
+ }
+ };
+
+ static EntUseAdapter monster_use = new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ if (self.enemy != null)
+ return;
+ if (self.health <= 0)
+ return;
+ if ((activator.flags & FL_NOTARGET) != 0)
+ return;
+ if ((null == activator.client) && 0 == (activator.monsterinfo.aiflags & AI_GOOD_GUY))
+ return;
+
+ // delay reaction so if the monster is teleported, its sound is still heard
+ self.enemy = activator;
+ FoundTarget(self);
+ }
+ };
+
+ static boolean monster_start(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return false;
+ }
+
+ if ((self.spawnflags & 4) != 0 && 0 == (self.monsterinfo.aiflags & AI_GOOD_GUY)) {
+ self.spawnflags &= ~4;
+ self.spawnflags |= 1;
+ // gi.dprintf("fixed spawnflags on %s at %s\n", self.classname, vtos(self.s.origin));
+ }
+
+ if (0 == (self.monsterinfo.aiflags & AI_GOOD_GUY))
+ level.total_monsters++;
+
+ self.nextthink = level.time + FRAMETIME;
+ self.svflags |= SVF_MONSTER;
+ self.s.renderfx |= RF_FRAMELERP;
+ self.takedamage = DAMAGE_AIM;
+ self.air_finished = level.time + 12;
+
+ // monster_use()
+ self.use = monster_use;
+
+ self.max_health = self.health;
+ self.clipmask = MASK_MONSTERSOLID;
+
+ self.s.skinnum = 0;
+ self.deadflag = DEAD_NO;
+ self.svflags &= ~SVF_DEADMONSTER;
+
+ if (self.monsterinfo.checkattack == null)
+ // M_CheckAttack;
+ self.monsterinfo.checkattack = M_CheckAttack;
+
+ Math3D.VectorCopy(self.s.origin, self.s.old_origin);
+
+ if (st.item != null) {
+ self.item = FindItemByClassname(st.item);
+ if (self.item == null)
+ gi.dprintf("" + self.classname + " at " + Lib.vtos(self.s.origin) + " has bad item: " + st.item + "\n");
+ }
+
+ // randomize what frame they start on
+ if (self.monsterinfo.currentmove != null)
+ self.s.frame =
+ self.monsterinfo.currentmove.firstframe
+ + (Lib.rand() % (self.monsterinfo.currentmove.lastframe - self.monsterinfo.currentmove.firstframe + 1));
+
+ return true;
+ }
+
+ /*
+ =============
+ range
+
+ returns the range catagorization of an entity reletive to self
+ 0 melee range, will become hostile even if back is turned
+ 1 visibility and infront, or visibility and show hostile
+ 2 infront and show hostile
+ 3 only triggered by damage
+ =============
+ */
+ static int range(edict_t self, edict_t other) {
+ float[] v = { 0, 0, 0 };
+ float len;
+
+ Math3D.VectorSubtract(self.s.origin, other.s.origin, v);
+ len = Math3D.VectorLength(v);
+ if (len < MELEE_DISTANCE)
+ return RANGE_MELEE;
+ if (len < 500)
+ return RANGE_NEAR;
+ if (len < 1000)
+ return RANGE_MID;
+ return RANGE_FAR;
+ }
+
+ /*
+ ===============
+ FindItemByClassname
+
+ ===============
+ */
+ static gitem_t FindItemByClassname(String classname) {
+
+ for (int i = 1; i < game.num_items; i++) {
+ gitem_t it = GameAI.itemlist[i];
+
+ if (it.classname == null)
+ continue;
+ if (it.classname.equalsIgnoreCase(classname))
+ return it;
+ }
+
+ return null;
+ }
+
+ /*
+ ===============
+ FindItem
+ ===============
+ */
+ //geht.
+ static gitem_t FindItem(String pickup_name) {
+ Com.Printf("FindItem:" + pickup_name + "\n");
+ for (int i = 1; i < game.num_items; i++) {
+ gitem_t it = GameAI.itemlist[i];
+
+ if (it.pickup_name == null)
+ continue;
+ if (it.pickup_name.equalsIgnoreCase(pickup_name))
+ return it;
+ }
+ Com.p("Item not found:" +pickup_name);
+ return null;
+ }
+
+ static int ArmorIndex(edict_t ent) {
+ if (ent.client == null)
+ return 0;
+
+ if (ent.client.pers.inventory[jacket_armor_index] > 0)
+ return jacket_armor_index;
+
+ if (ent.client.pers.inventory[combat_armor_index] > 0)
+ return combat_armor_index;
+
+ if (ent.client.pers.inventory[body_armor_index] > 0)
+ return body_armor_index;
+
+ return 0;
+ }
+
+ static int CheckArmor(edict_t ent, float[] point, float[] normal, int damage, int te_sparks, int dflags) {
+ gclient_t client;
+ int save;
+ int index;
+ gitem_t armor;
+
+ if (damage == 0)
+ return 0;
+
+ client = ent.client;
+
+ if (client != null)
+ return 0;
+
+ if ((dflags & DAMAGE_NO_ARMOR) != 0)
+ return 0;
+
+ index = ArmorIndex(ent);
+
+ if (index == 0)
+ return 0;
+
+ armor = GameAI.GetItemByIndex(index);
+ gitem_armor_t garmor = (gitem_armor_t) armor.info;
+
+ if (0 != (dflags & DAMAGE_ENERGY))
+ save = (int) Math.ceil(garmor.energy_protection * damage);
+ else
+ save = (int) Math.ceil(garmor.normal_protection * damage);
+
+ if (save >= client.pers.inventory[index])
+ save = client.pers.inventory[index];
+
+ if (save == 0)
+ return 0;
+
+ client.pers.inventory[index] -= save;
+ SpawnDamage(te_sparks, point, normal, save);
+
+ return save;
+ }
+
+ static boolean enemy_vis;
+ static boolean enemy_infront;
+ static int enemy_range;
+ static float enemy_yaw;
+
+ static void AttackFinished(edict_t self, float time) {
+ self.monsterinfo.attack_finished = level.time + time;
+ }
+
+ /*
+ =============
+ infront
+
+ returns true if the entity is in front (in sight) of self
+ =============
+ */
+ static boolean infront(edict_t self, edict_t other) {
+ float[] vec = { 0, 0, 0 };
+ float dot;
+ float[] forward = { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, null, null);
+ Math3D.VectorSubtract(other.s.origin, self.s.origin, vec);
+ Math3D.VectorNormalize(vec);
+ dot = Math3D.DotProduct(vec, forward);
+
+ if (dot > 0.3)
+ return true;
+ return false;
+ }
+
+ /*
+ =============
+ visible
+
+ returns 1 if the entity is visible to self, even if not infront ()
+ =============
+ */
+ public static boolean visible(edict_t self, edict_t other) {
+ float[] spot1 = { 0, 0, 0 };
+ float[] spot2 = { 0, 0, 0 };
+ trace_t trace;
+
+ Math3D.VectorCopy(self.s.origin, spot1);
+ spot1[2] += self.viewheight;
+ Math3D.VectorCopy(other.s.origin, spot2);
+ spot2[2] += other.viewheight;
+ trace = gi.trace(spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);
+
+ if (trace.fraction == 1.0)
+ return true;
+ return false;
+ }
+
+ /*
+ =================
+ AI_SetSightClient
+
+ Called once each frame to set level.sight_client to the
+ player to be checked for in findtarget.
+
+ If all clients are either dead or in notarget, sight_client
+ will be null.
+
+ In coop games, sight_client will cycle between the clients.
+ =================
+ */
+ static void AI_SetSightClient() {
+ edict_t ent;
+ int start, check;
+
+ if (level.sight_client == null)
+ start = 1;
+ else
+ start = level.sight_client.index;
+
+ check = start;
+ while (true) {
+ check++;
+ if (check > game.maxclients)
+ check = 1;
+ ent = g_edicts[check];
+
+ if (ent.inuse && ent.health > 0 && (ent.flags & FL_NOTARGET) == 0) {
+ level.sight_client = ent;
+ return; // got one
+ }
+ if (check == start) {
+ level.sight_client = null;
+ return; // nobody to see
+ }
+ }
+ }
+
+ /*
+ =============
+ ai_move
+
+ Move the specified distance at current facing.
+ This replaces the QC functions: ai_forward, ai_back, ai_pain, and ai_painforward
+ ==============
+ */
+ static void ai_move(edict_t self, float dist) {
+ M.M_walkmove(self, self.s.angles[YAW], dist);
+ }
+
+ /*
+ ===========
+ FindTarget
+
+ Self is currently not attacking anything, so try to find a target
+
+ Returns TRUE if an enemy was sighted
+
+ When a player fires a missile, the point of impact becomes a fakeplayer so
+ that monsters that see the impact will respond as if they had seen the
+ player.
+
+ To avoid spending too much time, only a single client (or fakeclient) is
+ checked each frame. This means multi player games will have slightly
+ slower noticing monsters.
+ ============
+ */
+ static boolean FindTarget(edict_t self) {
+ edict_t client;
+ boolean heardit;
+ int r;
+
+ if ((self.monsterinfo.aiflags & AI_GOOD_GUY) != 0) {
+ if (self.goalentity != null && self.goalentity.inuse && self.goalentity.classname != null) {
+ if (self.goalentity.classname.equals("target_actor"))
+ return false;
+ }
+
+ //FIXME look for monsters?
+ return false;
+ }
+
+ // if we're going to a combat point, just proceed
+ if ((self.monsterinfo.aiflags & AI_COMBAT_POINT) != 0)
+ return false;
+
+ // if the first spawnflag bit is set, the monster will only wake up on
+ // really seeing the player, not another monster getting angry or hearing
+ // something
+
+ // revised behavior so they will wake up if they "see" a player make a noise
+ // but not weapon impact/explosion noises
+
+ heardit = false;
+ if ((level.sight_entity_framenum >= (level.framenum - 1)) && 0 == (self.spawnflags & 1)) {
+ client = level.sight_entity;
+ if (client.enemy == self.enemy) {
+ return false;
+ }
+ }
+ else if (level.sound_entity_framenum >= (level.framenum - 1)) {
+ client = level.sound_entity;
+ heardit = true;
+ }
+ else if (null != (self.enemy) && (level.sound2_entity_framenum >= (level.framenum - 1)) && 0 != (self.spawnflags & 1)) {
+ client = level.sound2_entity;
+ heardit = true;
+ }
+ else {
+ client = level.sight_client;
+ if (client == null)
+ return false; // no clients to get mad at
+ }
+
+ // if the entity went away, forget it
+ if (!client.inuse)
+ return false;
+
+ if (client == self.enemy)
+ return true; // JDC false;
+
+ if (client.client != null) {
+ if ((client.flags & FL_NOTARGET) != 0)
+ return false;
+ }
+ else if ((client.svflags & SVF_MONSTER) != 0) {
+ if (client.enemy == null)
+ return false;
+ if ((client.enemy.flags & FL_NOTARGET) != 0)
+ return false;
+ }
+ else if (heardit) {
+ if ((client.owner.flags & FL_NOTARGET) != 0)
+ return false;
+ }
+ else
+ return false;
+
+ if (!heardit) {
+ r = range(self, client);
+
+ if (r == RANGE_FAR)
+ return false;
+
+ // this is where we would check invisibility
+
+ // is client in an spot too dark to be seen?
+ if (client.light_level <= 5)
+ return false;
+
+ if (!visible(self, client)) {
+ return false;
+ }
+
+ if (r == RANGE_NEAR) {
+ if (client.show_hostile < level.time && !infront(self, client)) {
+ return false;
+ }
+ }
+ else if (r == RANGE_MID) {
+ if (!infront(self, client)) {
+ return false;
+ }
+ }
+
+ self.enemy = client;
+
+ if (!self.enemy.classname.equals("player_noise")) {
+ self.monsterinfo.aiflags &= ~AI_SOUND_TARGET;
+
+ if (self.enemy.client == null) {
+ self.enemy = self.enemy.enemy;
+ if (self.enemy.client == null) {
+ self.enemy = null;
+ return false;
+ }
+ }
+ }
+ }
+ else // heardit
+ {
+ float[] temp = { 0, 0, 0 };
+
+ if ((self.spawnflags & 1) != 0) {
+ if (!visible(self, client))
+ return false;
+ }
+ else {
+ if (!gi.inPHS(self.s.origin, client.s.origin))
+ return false;
+ }
+
+ Math3D.VectorSubtract(client.s.origin, self.s.origin, temp);
+
+ if (Math3D.VectorLength(temp) > 1000) // too far to hear
+ {
+ return false;
+ }
+
+ // check area portals - if they are different and not connected then we can't hear it
+ if (client.areanum != self.areanum)
+ if (!gi.AreasConnected(self.areanum, client.areanum))
+ return false;
+
+ self.ideal_yaw = Math3D.vectoyaw(temp);
+ M.M_ChangeYaw(self);
+
+ // hunt the sound for a bit; hopefully find the real player
+ self.monsterinfo.aiflags |= AI_SOUND_TARGET;
+ self.enemy = client;
+ }
+
+ //
+ // got one
+ //
+ FoundTarget(self);
+
+ if (0 == (self.monsterinfo.aiflags & AI_SOUND_TARGET) && (self.monsterinfo.sight != null))
+ self.monsterinfo.sight.interact(self, self.enemy);
+
+ return true;
+ }
+
+ // ============================================================================
+
+ static void HuntTarget(edict_t self) {
+ float[] vec = { 0, 0, 0 };
+
+ self.goalentity = self.enemy;
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.stand.think(self);
+ else
+ self.monsterinfo.run.think(self);
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, vec);
+ self.ideal_yaw = Math3D.vectoyaw(vec);
+ // wait a while before first attack
+ if (0 == (self.monsterinfo.aiflags & AI_STAND_GROUND))
+ AttackFinished(self, 1);
+ }
+
+ public static void FoundTarget(edict_t self) {
+ // let other monsters see this monster for a while
+ if (self.enemy.client != null) {
+ level.sight_entity = self;
+ level.sight_entity_framenum = level.framenum;
+ level.sight_entity.light_level = 128;
+ }
+
+ self.show_hostile = (int) level.time + 1; // wake up other monsters
+
+ Math3D.VectorCopy(self.enemy.s.origin, self.monsterinfo.last_sighting);
+ self.monsterinfo.trail_time = level.time;
+
+ if (self.combattarget == null) {
+ HuntTarget(self);
+ return;
+ }
+
+ self.goalentity = self.movetarget = G_PickTarget(self.combattarget);
+ if (self.movetarget == null) {
+ self.goalentity = self.movetarget = self.enemy;
+ HuntTarget(self);
+ gi.dprintf("" + self.classname + "at " + Lib.vtos(self.s.origin) + ", combattarget " + self.combattarget + " not found\n");
+ return;
+ }
+
+ // clear out our combattarget, these are a one shot deal
+ self.combattarget = null;
+ self.monsterinfo.aiflags |= AI_COMBAT_POINT;
+
+ // clear the targetname, that point is ours!
+ self.movetarget.targetname = null;
+ self.monsterinfo.pausetime = 0;
+
+ // run for it
+ self.monsterinfo.run.think(self);
+ }
+
+ static boolean CheckTeamDamage(edict_t targ, edict_t attacker) {
+ //FIXME make the next line real and uncomment this block
+ // if ((ability to damage a teammate == OFF) && (targ's team == attacker's team))
+ return false;
+ }
+
+ /*
+ ============
+ T_RadiusDamage
+ ============
+ */
+ static void T_RadiusDamage(edict_t inflictor, edict_t attacker, float damage, edict_t ignore, float radius, int mod) {
+ float points;
+ EdictIterator edictit = null;
+
+ float[] v = { 0, 0, 0 };
+ float[] dir = { 0, 0, 0 };
+ ;
+
+ while ((edictit = findradius(edictit, inflictor.s.origin, radius)) != null) {
+ edict_t ent = edictit.o;
+ if (ent == ignore)
+ continue;
+ if (ent.takedamage == 0)
+ continue;
+
+ Math3D.VectorAdd(ent.mins, ent.maxs, v);
+ Math3D.VectorMA(ent.s.origin, 0.5f, v, v);
+ Math3D.VectorSubtract(inflictor.s.origin, v, v);
+ points = damage - 0.5f * Math3D.VectorLength(v);
+ if (ent == attacker)
+ points = points * 0.5f;
+ if (points > 0) {
+ if (CanDamage(ent, inflictor)) {
+ Math3D.VectorSubtract(ent.s.origin, inflictor.s.origin, dir);
+ T_Damage(
+ ent,
+ inflictor,
+ attacker,
+ dir,
+ inflictor.s.origin,
+ vec3_origin,
+ (int) points,
+ (int) points,
+ DAMAGE_RADIUS,
+ mod);
+ }
+ }
+ }
+ }
+}
diff --git a/src/jake2/game/GameWeapon.java b/src/jake2/game/GameWeapon.java
new file mode 100644
index 0000000..1d855a0
--- /dev/null
+++ b/src/jake2/game/GameWeapon.java
@@ -0,0 +1,566 @@
+/*
+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 12.11.2003 by RST.
+// $Id: GameWeapon.java,v 1.1 2004-07-07 19:59:06 hzi Exp $
+
+package jake2.game;
+
+import jake2.Defines;
+import jake2.util.*;
+
+public class GameWeapon extends GameAI {
+
+ /*
+ ===============
+ PlayerNoise
+
+ Each player can have two noise objects associated with it:
+ a personal noise (jumping, pain, weapon firing), and a weapon
+ target noise (bullet wall impacts)
+
+ Monsters that don't directly see the player can move
+ to a noise in hopes of seeing the player from there.
+ ===============
+ */
+ static void PlayerNoise(edict_t who, float[] where, int type) {
+ edict_t noise;
+
+ if (type == PNOISE_WEAPON) {
+ if (who.client.silencer_shots == 0) {
+ who.client.silencer_shots--;
+ return;
+ }
+ }
+
+ if (deathmatch.value != 0)
+ return;
+
+ if ((who.flags & FL_NOTARGET) != 0)
+ return;
+
+ if (who.mynoise == null) {
+ noise= G_Spawn();
+ noise.classname= "player_noise";
+ Math3D.VectorSet(noise.mins, -8, -8, -8);
+ Math3D.VectorSet(noise.maxs, 8, 8, 8);
+ noise.owner= who;
+ noise.svflags= SVF_NOCLIENT;
+ who.mynoise= noise;
+
+ noise= G_Spawn();
+ noise.classname= "player_noise";
+ Math3D.VectorSet(noise.mins, -8, -8, -8);
+ Math3D.VectorSet(noise.maxs, 8, 8, 8);
+ noise.owner= who;
+ noise.svflags= SVF_NOCLIENT;
+ who.mynoise2= noise;
+ }
+
+ if (type == PNOISE_SELF || type == PNOISE_WEAPON) {
+ noise= who.mynoise;
+ level.sound_entity= noise;
+ level.sound_entity_framenum= level.framenum;
+ } else // type == PNOISE_IMPACT
+ {
+ noise= who.mynoise2;
+ level.sound2_entity= noise;
+ level.sound2_entity_framenum= level.framenum;
+ }
+
+ Math3D.VectorCopy(where, noise.s.origin);
+ Math3D.VectorSubtract(where, noise.maxs, noise.absmin);
+ Math3D.VectorAdd(where, noise.maxs, noise.absmax);
+ noise.teleport_time= level.time;
+ gi.linkentity(noise);
+ }
+
+ /*
+ =================
+ check_dodge
+
+ This is a support routine used when a client is firing
+ a non-instant attack weapon. It checks to see if a
+ monster's dodge function should be called.
+ =================
+ */
+ static void check_dodge(edict_t self, float[] start, float[] dir, int speed) {
+ float[] end= { 0, 0, 0 };
+ float[] v= { 0, 0, 0 };
+ trace_t tr;
+ float eta;
+
+ // easy mode only ducks one quarter the time
+ if (skill.value == 0) {
+ if (Lib.random() > 0.25)
+ return;
+ }
+ Math3D.VectorMA(start, 8192, dir, end);
+ tr= gi.trace(start, null, null, end, self, MASK_SHOT);
+ if ((tr.ent != null)
+ && (tr.ent.svflags & SVF_MONSTER) != 0
+ && (tr.ent.health > 0)
+ && (null != tr.ent.monsterinfo.dodge)
+ && infront(tr.ent, self)) {
+ Math3D.VectorSubtract(tr.endpos, start, v);
+ eta= (Math3D.VectorLength(v) - tr.ent.maxs[0]) / speed;
+ tr.ent.monsterinfo.dodge.dodge(tr.ent, self, eta);
+ }
+ }
+
+ /*
+ =================
+ fire_blaster
+
+ Fires a single blaster bolt. Used by the blaster and hyper blaster.
+ =================
+ */
+ static EntTouchAdapter blaster_touch= new EntTouchAdapter() {
+
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ int mod;
+
+ if (other == self.owner)
+ return;
+
+ if (surf != null && (surf.flags & SURF_SKY) != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ if (self.owner.client != null)
+ PlayerNoise(self.owner, self.s.origin, PNOISE_IMPACT);
+
+ if (other.takedamage != 0) {
+ if ((self.spawnflags & 1) != 0)
+ mod= MOD_HYPERBLASTER;
+ else
+ mod= MOD_BLASTER;
+ T_Damage(
+ other,
+ self,
+ self.owner,
+ self.velocity,
+ self.s.origin,
+ plane.normal,
+ self.dmg,
+ 1,
+ DAMAGE_ENERGY,
+ mod);
+ } else {
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_BLASTER);
+ gi.WritePosition(self.s.origin);
+ if (plane == null)
+ gi.WriteDir(vec3_origin);
+ else
+ gi.WriteDir(plane.normal);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+ }
+
+ G_FreeEdict(self);
+ }
+ };
+
+ static EntThinkAdapter Grenade_Explode= new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] origin= { 0, 0, 0 };
+ int mod;
+
+ if (ent.owner.client != null)
+ PlayerNoise(ent.owner, ent.s.origin, PNOISE_IMPACT);
+
+ //FIXME: if we are onground then raise our Z just a bit since we are a point?
+ if (ent.enemy != null) {
+ float points= 0;
+ float[] v= { 0, 0, 0 };
+ float[] dir= { 0, 0, 0 };
+
+ Math3D.VectorAdd(ent.enemy.mins, ent.enemy.maxs, v);
+ Math3D.VectorMA(ent.enemy.s.origin, 0.5f, v, v);
+ Math3D.VectorSubtract(ent.s.origin, v, v);
+ points= ent.dmg - 0.5f * Math3D.VectorLength(v);
+ Math3D.VectorSubtract(ent.enemy.s.origin, ent.s.origin, dir);
+ if ((ent.spawnflags & 1) != 0)
+ mod= MOD_HANDGRENADE;
+ else
+ mod= MOD_GRENADE;
+ T_Damage(
+ ent.enemy,
+ ent,
+ ent.owner,
+ dir,
+ ent.s.origin,
+ vec3_origin,
+ (int) points,
+ (int) points,
+ DAMAGE_RADIUS,
+ mod);
+ }
+
+ if ((ent.spawnflags & 2) != 0)
+ mod= MOD_HELD_GRENADE;
+ else if ((ent.spawnflags & 1) != 0)
+ mod= MOD_HG_SPLASH;
+ else
+ mod= MOD_G_SPLASH;
+ T_RadiusDamage(ent, ent.owner, ent.dmg, ent.enemy, ent.dmg_radius, mod);
+
+ Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin);
+ gi.WriteByte(svc_temp_entity);
+ if (ent.waterlevel != 0) {
+ if (ent.groundentity != null)
+ gi.WriteByte(TE_GRENADE_EXPLOSION_WATER);
+ else
+ gi.WriteByte(TE_ROCKET_EXPLOSION_WATER);
+ } else {
+ if (ent.groundentity != null)
+ gi.WriteByte(TE_GRENADE_EXPLOSION);
+ else
+ gi.WriteByte(TE_ROCKET_EXPLOSION);
+ }
+ gi.WritePosition(origin);
+ gi.multicast(ent.s.origin, MULTICAST_PHS);
+
+ G_FreeEdict(ent);
+ return true;
+ }
+ };
+
+ static EntTouchAdapter Grenade_Touch= new EntTouchAdapter() {
+ public void touch(edict_t ent, edict_t other, cplane_t plane, csurface_t surf) {
+ if (other == ent.owner)
+ return;
+
+ if (surf != null && 0 != (surf.flags & SURF_SKY)) {
+ G_FreeEdict(ent);
+ return;
+ }
+
+ if (other.takedamage == 0) {
+ if ((ent.spawnflags & 1) != 0) {
+ if (Lib.random() > 0.5f)
+ gi.sound(
+ ent,
+ CHAN_VOICE,
+ gi.soundindex("weapons/hgrenb1a.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ else
+ gi.sound(
+ ent,
+ CHAN_VOICE,
+ gi.soundindex("weapons/hgrenb2a.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ } else {
+ gi.sound(
+ ent,
+ CHAN_VOICE,
+ gi.soundindex("weapons/grenlb1b.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ }
+ return;
+ }
+
+ ent.enemy= other;
+ Grenade_Explode.think(ent);
+ }
+ };
+
+ /*
+ =================
+ fire_rocket
+ =================
+ */
+ static EntTouchAdapter rocket_touch= new EntTouchAdapter() {
+ public void touch(edict_t ent, edict_t other, cplane_t plane, csurface_t surf) {
+ float[] origin= { 0, 0, 0 };
+ int n;
+
+ if (other == ent.owner)
+ return;
+
+ if (surf != null && (surf.flags & SURF_SKY) != 0) {
+ G_FreeEdict(ent);
+ return;
+ }
+
+ if (ent.owner.client != null)
+ PlayerNoise(ent.owner, ent.s.origin, PNOISE_IMPACT);
+
+ // calculate position for the explosion entity
+ Math3D.VectorMA(ent.s.origin, -0.02f, ent.velocity, origin);
+
+ if (other.takedamage != 0) {
+ T_Damage(
+ other,
+ ent,
+ ent.owner,
+ ent.velocity,
+ ent.s.origin,
+ plane.normal,
+ ent.dmg,
+ 0,
+ 0,
+ MOD_ROCKET);
+ } else {
+ // don't throw any debris in net games
+ if (deathmatch.value == 0 && 0 == coop.value) {
+ if ((surf != null)
+ && 0
+ == (surf.flags
+ & (SURF_WARP | SURF_TRANS33 | SURF_TRANS66 | SURF_FLOWING))) {
+ n= Lib.rand() % 5;
+ while (n-- > 0)
+ ThrowDebris(ent, "models/objects/debris2/tris.md2", 2, ent.s.origin);
+ }
+ }
+ }
+
+ T_RadiusDamage(ent, ent.owner, ent.radius_dmg, other, ent.dmg_radius, MOD_R_SPLASH);
+
+ gi.WriteByte(svc_temp_entity);
+ if (ent.waterlevel != 0)
+ gi.WriteByte(TE_ROCKET_EXPLOSION_WATER);
+ else
+ gi.WriteByte(TE_ROCKET_EXPLOSION);
+ gi.WritePosition(origin);
+ gi.multicast(ent.s.origin, MULTICAST_PHS);
+
+ G_FreeEdict(ent);
+ }
+ };
+
+ /*
+ =================
+ fire_bfg
+ =================
+ */
+ static EntThinkAdapter bfg_explode= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent;
+ float points;
+ float[] v= { 0, 0, 0 };
+ float dist;
+
+ EdictIterator edit= null;
+
+ if (self.s.frame == 0) {
+ // the BFG effect
+ ent= null;
+ while ((edit= findradius(edit, self.s.origin, self.dmg_radius)) != null) {
+ ent= edit.o;
+ if (ent.takedamage == 0)
+ continue;
+ if (ent == self.owner)
+ continue;
+ if (!CanDamage(ent, self))
+ continue;
+ if (!CanDamage(ent, self.owner))
+ continue;
+
+ Math3D.VectorAdd(ent.mins, ent.maxs, v);
+ Math3D.VectorMA(ent.s.origin, 0.5f, v, v);
+ Math3D.VectorSubtract(self.s.origin, v, v);
+ dist= Math3D.VectorLength(v);
+ points= (float) (self.radius_dmg * (1.0 - Math.sqrt(dist / self.dmg_radius)));
+ if (ent == self.owner)
+ points= points * 0.5f;
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_BFG_EXPLOSION);
+ gi.WritePosition(ent.s.origin);
+ gi.multicast(ent.s.origin, MULTICAST_PHS);
+ T_Damage(
+ ent,
+ self,
+ self.owner,
+ self.velocity,
+ ent.s.origin,
+ vec3_origin,
+ (int) points,
+ 0,
+ DAMAGE_ENERGY,
+ MOD_BFG_EFFECT);
+ }
+ }
+
+ self.nextthink= level.time + FRAMETIME;
+ self.s.frame++;
+ if (self.s.frame == 5)
+ self.think= G_FreeEdictA;
+ return true;
+
+ }
+ };
+
+ static EntTouchAdapter bfg_touch= new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (other == self.owner)
+ return;
+
+ if (surf != null && (surf.flags & SURF_SKY) != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ if (self.owner.client != null)
+ PlayerNoise(self.owner, self.s.origin, PNOISE_IMPACT);
+
+ // core explosion - prevents firing it into the wall/floor
+ if (other.takedamage != 0)
+ T_Damage(
+ other,
+ self,
+ self.owner,
+ self.velocity,
+ self.s.origin,
+ plane.normal,
+ 200,
+ 0,
+ 0,
+ MOD_BFG_BLAST);
+ T_RadiusDamage(self, self.owner, 200, other, 100, MOD_BFG_BLAST);
+
+ gi.sound(self, CHAN_VOICE, gi.soundindex("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
+ self.solid= SOLID_NOT;
+ self.touch= null;
+ Math3D.VectorMA(self.s.origin, -1 * FRAMETIME, self.velocity, self.s.origin);
+ Math3D.VectorClear(self.velocity);
+ self.s.modelindex= gi.modelindex("sprites/s_bfg3.sp2");
+ self.s.frame= 0;
+ self.s.sound= 0;
+ self.s.effects &= ~EF_ANIM_ALLFAST;
+ self.think= bfg_explode;
+ self.nextthink= level.time + FRAMETIME;
+ self.enemy= other;
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_BFG_BIGEXPLOSION);
+ gi.WritePosition(self.s.origin);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+ }
+ };
+
+ static EntThinkAdapter bfg_think= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent;
+ edict_t ignore;
+ float[] point= { 0, 0, 0 };
+ float[] dir= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+ float[] end= { 0, 0, 0 };
+ int dmg;
+ trace_t tr;
+
+ if (deathmatch.value != 0)
+ dmg= 5;
+ else
+ dmg= 10;
+
+ EdictIterator edit= null;
+ while ((edit= findradius(edit, self.s.origin, 256)) != null) {
+ ent= edit.o;
+
+ if (ent == self)
+ continue;
+
+ if (ent == self.owner)
+ continue;
+
+ if (ent.takedamage == 0)
+ continue;
+
+ if (0 == (ent.svflags & SVF_MONSTER)
+ && (null == ent.client)
+ && (Lib.strcmp(ent.classname, "misc_explobox") != 0))
+ continue;
+
+ Math3D.VectorMA(ent.absmin, 0.5f, ent.size, point);
+
+ Math3D.VectorSubtract(point, self.s.origin, dir);
+ Math3D.VectorNormalize(dir);
+
+ ignore= self;
+ Math3D.VectorCopy(self.s.origin, start);
+ Math3D.VectorMA(start, 2048, dir, end);
+ while (true) {
+ tr=
+ gi.trace(
+ start,
+ null,
+ null,
+ end,
+ ignore,
+ CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_DEADMONSTER);
+
+ if (null == tr.ent)
+ break;
+
+ // hurt it if we can
+ if ((tr.ent.takedamage != 0)
+ && 0 == (tr.ent.flags & FL_IMMUNE_LASER)
+ && (tr.ent != self.owner))
+ T_Damage(
+ tr.ent,
+ self,
+ self.owner,
+ dir,
+ tr.endpos,
+ vec3_origin,
+ dmg,
+ 1,
+ DAMAGE_ENERGY,
+ MOD_BFG_LASER);
+
+ // if we hit something that's not a monster or player we're done
+ if (0 == (tr.ent.svflags & SVF_MONSTER) && (null == tr.ent.client)) {
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_LASER_SPARKS);
+ gi.WriteByte(4);
+ gi.WritePosition(tr.endpos);
+ gi.WriteDir(tr.plane.normal);
+ gi.WriteByte(self.s.skinnum);
+ gi.multicast(tr.endpos, MULTICAST_PVS);
+ break;
+ }
+
+ ignore= tr.ent;
+ Math3D.VectorCopy(tr.endpos, start);
+ }
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_BFG_LASER);
+ gi.WritePosition(self.s.origin);
+ gi.WritePosition(tr.endpos);
+ gi.multicast(self.s.origin, MULTICAST_PHS);
+ }
+
+ self.nextthink= level.time + FRAMETIME;
+ return true;
+ }
+ };
+
+}
diff --git a/src/jake2/game/Info.java b/src/jake2/game/Info.java
new file mode 100644
index 0000000..7b23ed6
--- /dev/null
+++ b/src/jake2/game/Info.java
@@ -0,0 +1,263 @@
+/*
+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 27.12.2003 by RST.
+// $Id: Info.java,v 1.1 2004-07-07 19:59:07 hzi Exp $
+
+package jake2.game;
+
+import java.util.StringTokenizer;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class Info extends PlayerView {
+
+
+ public static String Info_ValueForKey(String s, String key) {
+
+ StringTokenizer tk = new StringTokenizer(s, "\\");
+
+ while (tk.hasMoreTokens()) {
+ String key1 = tk.nextToken();
+
+ if (!tk.hasMoreTokens()) {
+ Com.Printf("MISSING VALUE\n");
+ return s;
+ }
+ String value1 = tk.nextToken();
+
+ if (key.equals(key1))
+ return value1;
+ }
+
+ return "";
+ }
+
+ /** DANGEROUS, returns the modified userinfo string, was pointer-pointer manipulation first*/
+ public static String Info_SetValueForKey1(String s, String key, String value) {
+
+ if (value == null || value.length() == 0)
+ return s;
+
+ if (key.indexOf('\\') != -1 || value.indexOf('\\') != -1) {
+ Com.Printf("Can't use keys or values with a \\\n");
+ return s;
+ }
+
+ if (key.indexOf(';') != -1) {
+ Com.Printf("Can't use keys or values with a semicolon\n");
+ return s;
+ }
+
+ if (key.indexOf('"') != -1 || value.indexOf('"') != -1) {
+ Com.Printf("Can't use keys or values with a \"\n");
+ return s;
+ }
+
+ if (strlen(key) > MAX_INFO_KEY - 1 || strlen(value) > MAX_INFO_KEY - 1) {
+ Com.Printf("Keys and values must be < 64 characters.\n");
+ return s;
+ }
+
+ StringBuffer sb = new StringBuffer(Info_RemoveKey1(s, key));
+
+ if (sb.length() + 2 + key.length() + value.length() > Defines.MAX_INFO_STRING){
+
+
+ Com.Printf("Info string length exceeded\n");
+ return s;
+ }
+
+ sb.append('\\').append(key).append('\\').append(value);
+
+ return sb.toString();
+ }
+
+
+
+ /** DANGEROUS, returns now the modified userinfo string.*/
+ public static String Info_RemoveKey1(String s, String key) {
+
+ StringBuffer sb = new StringBuffer(512);
+
+ if (key.indexOf('\\') != -1) {
+ Com.Printf("Can't use a key with a \\\n");
+ return s;
+ }
+
+ StringTokenizer tk = new StringTokenizer(s, "\\");
+
+ while (tk.hasMoreTokens()) {
+ String key1 = tk.nextToken();
+
+ if (!tk.hasMoreTokens()) {
+ Com.Printf("MISSING VALUE\n");
+ return s;
+ }
+ String value1 = tk.nextToken();
+
+ if (!key.equals(key1))
+ sb.append('\\').append(key1).append('\\').append(value1);
+ }
+
+ return sb.toString();
+
+ //some old code follows
+
+ /*
+ char * start;
+ char pkey[512];
+ char value[512];
+ char * o;
+
+ if (key.indexOf('\\')!=-1) {
+ Com.Printf ("Can't use a key with a \\\n");
+ return s;
+ }
+
+ while () {
+ start = s;
+ if (* s == '\\')
+ s++;
+ o = pkey;
+ while (* s != '\\') {
+ if (!* s)
+ return;
+ * o++ = * s++;
+ }
+ * o = 0;
+ s++;
+
+ o = value;
+ while (* s != '\\' && * s) {
+ if (!* s)
+ return;
+ * o++ = * s++;
+ }
+ * o = 0;
+
+ if (!strcmp(key, pkey)) {
+ strcpy(start, s); // remove this part
+ return;
+ }
+
+ if (!* s)
+ return;
+ }
+ */
+ }
+
+ /*
+ ==================
+ Info_Validate
+
+ Some characters are illegal in info strings because they
+ can mess up the server's parsing
+ ==================
+ */
+ public static boolean Info_Validate(String s) {
+ if (s.indexOf('"') != -1)
+ //return false;
+ if (s.indexOf(';') != -1)
+ return false;
+ return true;
+ }
+
+ private static String fillspaces = " ";
+
+
+ public static void Print(String s) {
+
+ StringBuffer sb = new StringBuffer(512);
+ StringTokenizer tk = new StringTokenizer(s, "\\");
+
+ while (tk.hasMoreTokens()) {
+
+ String key1 = tk.nextToken();
+
+ if (!tk.hasMoreTokens()) {
+ Com.Printf("MISSING VALUE\n");
+ return;
+ }
+
+ String value1 = tk.nextToken();
+
+ sb.append(key1);
+
+ int len = key1.length();
+
+ if (len < 20) {
+ sb.append(fillspaces.substring(len));
+ }
+
+ sb.append('=').append(value1).append('\n');
+ }
+
+ Com.Printf(sb.toString());
+
+ /* some old code follows
+
+ char * o;
+ int l;
+
+ if (* s == '\\')
+ s++;
+ while (* s) {
+ o = key;
+ while (* s && * s != '\\')
+ * o++ = * s++;
+
+ l = o - key;
+ if (l < 20) {
+ memset(o, ' ', 20 - l);
+ key[20] = 0;
+ }
+ else
+ * o = 0;
+ Com_Printf("%s", key);
+
+ if (!* s) {
+ Com_Printf("MISSING VALUE\n");
+ return;
+ }
+
+ o = value;
+ s++;
+ while (* s && * s != '\\')
+ * o++ = * s++;
+ * o = 0;
+
+ if (* s)
+ s++;
+ Com_Printf("%s\n", value);
+ }
+ */
+ }
+
+ public static void testintern(StringBuffer in) {
+ in.setLength(0);
+ in.append("123!");
+ }
+
+}
diff --git a/src/jake2/game/ItemDropAdapter.java b/src/jake2/game/ItemDropAdapter.java
new file mode 100644
index 0000000..4078fcd
--- /dev/null
+++ b/src/jake2/game/ItemDropAdapter.java
@@ -0,0 +1,29 @@
+/*
+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 08.11.2003 by RST.
+// $Id: ItemDropAdapter.java,v 1.1 2004-07-07 19:59:07 hzi Exp $
+
+package jake2.game;
+
+public class ItemDropAdapter extends SuperAdapter {
+ void drop(edict_t ent, gitem_t item) {
+ }
+}
diff --git a/src/jake2/game/ItemUseAdapter.java b/src/jake2/game/ItemUseAdapter.java
new file mode 100644
index 0000000..71c0ebf
--- /dev/null
+++ b/src/jake2/game/ItemUseAdapter.java
@@ -0,0 +1,29 @@
+/*
+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 08.11.2003 by RST.
+// $Id: ItemUseAdapter.java,v 1.1 2004-07-07 19:59:07 hzi Exp $
+
+package jake2.game;
+
+class ItemUseAdapter extends SuperAdapter {
+ public void use(edict_t ent, gitem_t item) {
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/LittleEndianHandler.java b/src/jake2/game/LittleEndianHandler.java
new file mode 100644
index 0000000..932a84b
--- /dev/null
+++ b/src/jake2/game/LittleEndianHandler.java
@@ -0,0 +1,56 @@
+/*
+ * LittleEndianHandler.java
+ * Copyright (C) 2003
+ *
+ * $Id: LittleEndianHandler.java,v 1.1 2004-07-07 19:59:07 hzi Exp $
+ */
+package jake2.game;
+
+/**
+ * LittleEndianHandler</code>
+ */
+public final class LittleEndianHandler extends EndianHandler {
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#BigFloat(float)
+ */
+ public float BigFloat(float f) {
+ return swapFloat(f);
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#BigShort(short)
+ */
+ public short BigShort(short s) {
+ return swapShort(s);
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#BigLong(int)
+ */
+ public int BigLong(int i) {
+ return swapInt(i);
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#LittleFloat(float)
+ */
+ public float LittleFloat(float f) {
+ return f;
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#LittleShort(short)
+ */
+ public short LittleShort(short s) {
+ return s;
+ }
+
+ /* (non-Javadoc)
+ * @see quake2.EndianHandler#LittleLong(int)
+ */
+ public int LittleLong(int i) {
+ return i;
+ }
+
+}
diff --git a/src/jake2/game/M_Actor.java b/src/jake2/game/M_Actor.java
new file mode 100644
index 0000000..3eb2eb6
--- /dev/null
+++ b/src/jake2/game/M_Actor.java
@@ -0,0 +1,1129 @@
+/*
+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 11.11.2003 by RST.
+// $Id: M_Actor.java,v 1.1 2004-07-07 19:59:07 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Actor extends GameAI {
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_attak01= 0;
+ public final static int FRAME_attak02= 1;
+ public final static int FRAME_attak03= 2;
+ public final static int FRAME_attak04= 3;
+ public final static int FRAME_death101= 4;
+ public final static int FRAME_death102= 5;
+ public final static int FRAME_death103= 6;
+ public final static int FRAME_death104= 7;
+ public final static int FRAME_death105= 8;
+ public final static int FRAME_death106= 9;
+ public final static int FRAME_death107= 10;
+ public final static int FRAME_death201= 11;
+ public final static int FRAME_death202= 12;
+ public final static int FRAME_death203= 13;
+ public final static int FRAME_death204= 14;
+ public final static int FRAME_death205= 15;
+ public final static int FRAME_death206= 16;
+ public final static int FRAME_death207= 17;
+ public final static int FRAME_death208= 18;
+ public final static int FRAME_death209= 19;
+ public final static int FRAME_death210= 20;
+ public final static int FRAME_death211= 21;
+ public final static int FRAME_death212= 22;
+ public final static int FRAME_death213= 23;
+ public final static int FRAME_death301= 24;
+ public final static int FRAME_death302= 25;
+ public final static int FRAME_death303= 26;
+ public final static int FRAME_death304= 27;
+ public final static int FRAME_death305= 28;
+ public final static int FRAME_death306= 29;
+ public final static int FRAME_death307= 30;
+ public final static int FRAME_death308= 31;
+ public final static int FRAME_death309= 32;
+ public final static int FRAME_death310= 33;
+ public final static int FRAME_death311= 34;
+ public final static int FRAME_death312= 35;
+ public final static int FRAME_death313= 36;
+ public final static int FRAME_death314= 37;
+ public final static int FRAME_death315= 38;
+ public final static int FRAME_flip01= 39;
+ public final static int FRAME_flip02= 40;
+ public final static int FRAME_flip03= 41;
+ public final static int FRAME_flip04= 42;
+ public final static int FRAME_flip05= 43;
+ public final static int FRAME_flip06= 44;
+ public final static int FRAME_flip07= 45;
+ public final static int FRAME_flip08= 46;
+ public final static int FRAME_flip09= 47;
+ public final static int FRAME_flip10= 48;
+ public final static int FRAME_flip11= 49;
+ public final static int FRAME_flip12= 50;
+ public final static int FRAME_flip13= 51;
+ public final static int FRAME_flip14= 52;
+ public final static int FRAME_grenad01= 53;
+ public final static int FRAME_grenad02= 54;
+ public final static int FRAME_grenad03= 55;
+ public final static int FRAME_grenad04= 56;
+ public final static int FRAME_grenad05= 57;
+ public final static int FRAME_grenad06= 58;
+ public final static int FRAME_grenad07= 59;
+ public final static int FRAME_grenad08= 60;
+ public final static int FRAME_grenad09= 61;
+ public final static int FRAME_grenad10= 62;
+ public final static int FRAME_grenad11= 63;
+ public final static int FRAME_grenad12= 64;
+ public final static int FRAME_grenad13= 65;
+ public final static int FRAME_grenad14= 66;
+ public final static int FRAME_grenad15= 67;
+ public final static int FRAME_jump01= 68;
+ public final static int FRAME_jump02= 69;
+ public final static int FRAME_jump03= 70;
+ public final static int FRAME_jump04= 71;
+ public final static int FRAME_jump05= 72;
+ public final static int FRAME_jump06= 73;
+ public final static int FRAME_pain101= 74;
+ public final static int FRAME_pain102= 75;
+ public final static int FRAME_pain103= 76;
+ public final static int FRAME_pain201= 77;
+ public final static int FRAME_pain202= 78;
+ public final static int FRAME_pain203= 79;
+ public final static int FRAME_pain301= 80;
+ public final static int FRAME_pain302= 81;
+ public final static int FRAME_pain303= 82;
+ public final static int FRAME_push01= 83;
+ public final static int FRAME_push02= 84;
+ public final static int FRAME_push03= 85;
+ public final static int FRAME_push04= 86;
+ public final static int FRAME_push05= 87;
+ public final static int FRAME_push06= 88;
+ public final static int FRAME_push07= 89;
+ public final static int FRAME_push08= 90;
+ public final static int FRAME_push09= 91;
+ public final static int FRAME_run01= 92;
+ public final static int FRAME_run02= 93;
+ public final static int FRAME_run03= 94;
+ public final static int FRAME_run04= 95;
+ public final static int FRAME_run05= 96;
+ public final static int FRAME_run06= 97;
+ public final static int FRAME_run07= 98;
+ public final static int FRAME_run08= 99;
+ public final static int FRAME_run09= 100;
+ public final static int FRAME_run10= 101;
+ public final static int FRAME_run11= 102;
+ public final static int FRAME_run12= 103;
+ public final static int FRAME_runs01= 104;
+ public final static int FRAME_runs02= 105;
+ public final static int FRAME_runs03= 106;
+ public final static int FRAME_runs04= 107;
+ public final static int FRAME_runs05= 108;
+ public final static int FRAME_runs06= 109;
+ public final static int FRAME_runs07= 110;
+ public final static int FRAME_runs08= 111;
+ public final static int FRAME_runs09= 112;
+ public final static int FRAME_runs10= 113;
+ public final static int FRAME_runs11= 114;
+ public final static int FRAME_runs12= 115;
+ public final static int FRAME_salute01= 116;
+ public final static int FRAME_salute02= 117;
+ public final static int FRAME_salute03= 118;
+ public final static int FRAME_salute04= 119;
+ public final static int FRAME_salute05= 120;
+ public final static int FRAME_salute06= 121;
+ public final static int FRAME_salute07= 122;
+ public final static int FRAME_salute08= 123;
+ public final static int FRAME_salute09= 124;
+ public final static int FRAME_salute10= 125;
+ public final static int FRAME_salute11= 126;
+ public final static int FRAME_salute12= 127;
+ public final static int FRAME_stand101= 128;
+ public final static int FRAME_stand102= 129;
+ public final static int FRAME_stand103= 130;
+ public final static int FRAME_stand104= 131;
+ public final static int FRAME_stand105= 132;
+ public final static int FRAME_stand106= 133;
+ public final static int FRAME_stand107= 134;
+ public final static int FRAME_stand108= 135;
+ public final static int FRAME_stand109= 136;
+ public final static int FRAME_stand110= 137;
+ public final static int FRAME_stand111= 138;
+ public final static int FRAME_stand112= 139;
+ public final static int FRAME_stand113= 140;
+ public final static int FRAME_stand114= 141;
+ public final static int FRAME_stand115= 142;
+ public final static int FRAME_stand116= 143;
+ public final static int FRAME_stand117= 144;
+ public final static int FRAME_stand118= 145;
+ public final static int FRAME_stand119= 146;
+ public final static int FRAME_stand120= 147;
+ public final static int FRAME_stand121= 148;
+ public final static int FRAME_stand122= 149;
+ public final static int FRAME_stand123= 150;
+ public final static int FRAME_stand124= 151;
+ public final static int FRAME_stand125= 152;
+ public final static int FRAME_stand126= 153;
+ public final static int FRAME_stand127= 154;
+ public final static int FRAME_stand128= 155;
+ public final static int FRAME_stand129= 156;
+ public final static int FRAME_stand130= 157;
+ public final static int FRAME_stand131= 158;
+ public final static int FRAME_stand132= 159;
+ public final static int FRAME_stand133= 160;
+ public final static int FRAME_stand134= 161;
+ public final static int FRAME_stand135= 162;
+ public final static int FRAME_stand136= 163;
+ public final static int FRAME_stand137= 164;
+ public final static int FRAME_stand138= 165;
+ public final static int FRAME_stand139= 166;
+ public final static int FRAME_stand140= 167;
+ public final static int FRAME_stand201= 168;
+ public final static int FRAME_stand202= 169;
+ public final static int FRAME_stand203= 170;
+ public final static int FRAME_stand204= 171;
+ public final static int FRAME_stand205= 172;
+ public final static int FRAME_stand206= 173;
+ public final static int FRAME_stand207= 174;
+ public final static int FRAME_stand208= 175;
+ public final static int FRAME_stand209= 176;
+ public final static int FRAME_stand210= 177;
+ public final static int FRAME_stand211= 178;
+ public final static int FRAME_stand212= 179;
+ public final static int FRAME_stand213= 180;
+ public final static int FRAME_stand214= 181;
+ public final static int FRAME_stand215= 182;
+ public final static int FRAME_stand216= 183;
+ public final static int FRAME_stand217= 184;
+ public final static int FRAME_stand218= 185;
+ public final static int FRAME_stand219= 186;
+ public final static int FRAME_stand220= 187;
+ public final static int FRAME_stand221= 188;
+ public final static int FRAME_stand222= 189;
+ public final static int FRAME_stand223= 190;
+ public final static int FRAME_swim01= 191;
+ public final static int FRAME_swim02= 192;
+ public final static int FRAME_swim03= 193;
+ public final static int FRAME_swim04= 194;
+ public final static int FRAME_swim05= 195;
+ public final static int FRAME_swim06= 196;
+ public final static int FRAME_swim07= 197;
+ public final static int FRAME_swim08= 198;
+ public final static int FRAME_swim09= 199;
+ public final static int FRAME_swim10= 200;
+ public final static int FRAME_swim11= 201;
+ public final static int FRAME_swim12= 202;
+ public final static int FRAME_sw_atk01= 203;
+ public final static int FRAME_sw_atk02= 204;
+ public final static int FRAME_sw_atk03= 205;
+ public final static int FRAME_sw_atk04= 206;
+ public final static int FRAME_sw_atk05= 207;
+ public final static int FRAME_sw_atk06= 208;
+ public final static int FRAME_sw_pan01= 209;
+ public final static int FRAME_sw_pan02= 210;
+ public final static int FRAME_sw_pan03= 211;
+ public final static int FRAME_sw_pan04= 212;
+ public final static int FRAME_sw_pan05= 213;
+ public final static int FRAME_sw_std01= 214;
+ public final static int FRAME_sw_std02= 215;
+ public final static int FRAME_sw_std03= 216;
+ public final static int FRAME_sw_std04= 217;
+ public final static int FRAME_sw_std05= 218;
+ public final static int FRAME_sw_std06= 219;
+ public final static int FRAME_sw_std07= 220;
+ public final static int FRAME_sw_std08= 221;
+ public final static int FRAME_sw_std09= 222;
+ public final static int FRAME_sw_std10= 223;
+ public final static int FRAME_sw_std11= 224;
+ public final static int FRAME_sw_std12= 225;
+ public final static int FRAME_sw_std13= 226;
+ public final static int FRAME_sw_std14= 227;
+ public final static int FRAME_sw_std15= 228;
+ public final static int FRAME_sw_std16= 229;
+ public final static int FRAME_sw_std17= 230;
+ public final static int FRAME_sw_std18= 231;
+ public final static int FRAME_sw_std19= 232;
+ public final static int FRAME_sw_std20= 233;
+ public final static int FRAME_taunt01= 234;
+ public final static int FRAME_taunt02= 235;
+ public final static int FRAME_taunt03= 236;
+ public final static int FRAME_taunt04= 237;
+ public final static int FRAME_taunt05= 238;
+ public final static int FRAME_taunt06= 239;
+ public final static int FRAME_taunt07= 240;
+ public final static int FRAME_taunt08= 241;
+ public final static int FRAME_taunt09= 242;
+ public final static int FRAME_taunt10= 243;
+ public final static int FRAME_taunt11= 244;
+ public final static int FRAME_taunt12= 245;
+ public final static int FRAME_taunt13= 246;
+ public final static int FRAME_taunt14= 247;
+ public final static int FRAME_taunt15= 248;
+ public final static int FRAME_taunt16= 249;
+ public final static int FRAME_taunt17= 250;
+ public final static int FRAME_walk01= 251;
+ public final static int FRAME_walk02= 252;
+ public final static int FRAME_walk03= 253;
+ public final static int FRAME_walk04= 254;
+ public final static int FRAME_walk05= 255;
+ public final static int FRAME_walk06= 256;
+ public final static int FRAME_walk07= 257;
+ public final static int FRAME_walk08= 258;
+ public final static int FRAME_walk09= 259;
+ public final static int FRAME_walk10= 260;
+ public final static int FRAME_walk11= 261;
+ public final static int FRAME_wave01= 262;
+ public final static int FRAME_wave02= 263;
+ public final static int FRAME_wave03= 264;
+ public final static int FRAME_wave04= 265;
+ public final static int FRAME_wave05= 266;
+ public final static int FRAME_wave06= 267;
+ public final static int FRAME_wave07= 268;
+ public final static int FRAME_wave08= 269;
+ public final static int FRAME_wave09= 270;
+ public final static int FRAME_wave10= 271;
+ public final static int FRAME_wave11= 272;
+ public final static int FRAME_wave12= 273;
+ public final static int FRAME_wave13= 274;
+ public final static int FRAME_wave14= 275;
+ public final static int FRAME_wave15= 276;
+ public final static int FRAME_wave16= 277;
+ public final static int FRAME_wave17= 278;
+ public final static int FRAME_wave18= 279;
+ public final static int FRAME_wave19= 280;
+ public final static int FRAME_wave20= 281;
+ public final static int FRAME_wave21= 282;
+ public final static int FRAME_bl_atk01= 283;
+ public final static int FRAME_bl_atk02= 284;
+ public final static int FRAME_bl_atk03= 285;
+ public final static int FRAME_bl_atk04= 286;
+ public final static int FRAME_bl_atk05= 287;
+ public final static int FRAME_bl_atk06= 288;
+ public final static int FRAME_bl_flp01= 289;
+ public final static int FRAME_bl_flp02= 290;
+ public final static int FRAME_bl_flp13= 291;
+ public final static int FRAME_bl_flp14= 292;
+ public final static int FRAME_bl_flp15= 293;
+ public final static int FRAME_bl_jmp01= 294;
+ public final static int FRAME_bl_jmp02= 295;
+ public final static int FRAME_bl_jmp03= 296;
+ public final static int FRAME_bl_jmp04= 297;
+ public final static int FRAME_bl_jmp05= 298;
+ public final static int FRAME_bl_jmp06= 299;
+ public final static int FRAME_bl_pn101= 300;
+ public final static int FRAME_bl_pn102= 301;
+ public final static int FRAME_bl_pn103= 302;
+ public final static int FRAME_bl_pn201= 303;
+ public final static int FRAME_bl_pn202= 304;
+ public final static int FRAME_bl_pn203= 305;
+ public final static int FRAME_bl_pn301= 306;
+ public final static int FRAME_bl_pn302= 307;
+ public final static int FRAME_bl_pn303= 308;
+ public final static int FRAME_bl_psh08= 309;
+ public final static int FRAME_bl_psh09= 310;
+ public final static int FRAME_bl_run01= 311;
+ public final static int FRAME_bl_run02= 312;
+ public final static int FRAME_bl_run03= 313;
+ public final static int FRAME_bl_run04= 314;
+ public final static int FRAME_bl_run05= 315;
+ public final static int FRAME_bl_run06= 316;
+ public final static int FRAME_bl_run07= 317;
+ public final static int FRAME_bl_run08= 318;
+ public final static int FRAME_bl_run09= 319;
+ public final static int FRAME_bl_run10= 320;
+ public final static int FRAME_bl_run11= 321;
+ public final static int FRAME_bl_run12= 322;
+ public final static int FRAME_bl_rns03= 323;
+ public final static int FRAME_bl_rns04= 324;
+ public final static int FRAME_bl_rns05= 325;
+ public final static int FRAME_bl_rns06= 326;
+ public final static int FRAME_bl_rns07= 327;
+ public final static int FRAME_bl_rns08= 328;
+ public final static int FRAME_bl_rns09= 329;
+ public final static int FRAME_bl_sal10= 330;
+ public final static int FRAME_bl_sal11= 331;
+ public final static int FRAME_bl_sal12= 332;
+ public final static int FRAME_bl_std01= 333;
+ public final static int FRAME_bl_std02= 334;
+ public final static int FRAME_bl_std03= 335;
+ public final static int FRAME_bl_std04= 336;
+ public final static int FRAME_bl_std05= 337;
+ public final static int FRAME_bl_std06= 338;
+ public final static int FRAME_bl_std07= 339;
+ public final static int FRAME_bl_std08= 340;
+ public final static int FRAME_bl_std09= 341;
+ public final static int FRAME_bl_std10= 342;
+ public final static int FRAME_bl_std11= 343;
+ public final static int FRAME_bl_std12= 344;
+ public final static int FRAME_bl_std13= 345;
+ public final static int FRAME_bl_std14= 346;
+ public final static int FRAME_bl_std15= 347;
+ public final static int FRAME_bl_std16= 348;
+ public final static int FRAME_bl_std17= 349;
+ public final static int FRAME_bl_std18= 350;
+ public final static int FRAME_bl_std19= 351;
+ public final static int FRAME_bl_std20= 352;
+ public final static int FRAME_bl_std21= 353;
+ public final static int FRAME_bl_std22= 354;
+ public final static int FRAME_bl_std23= 355;
+ public final static int FRAME_bl_std24= 356;
+ public final static int FRAME_bl_std25= 357;
+ public final static int FRAME_bl_std26= 358;
+ public final static int FRAME_bl_std27= 359;
+ public final static int FRAME_bl_std28= 360;
+ public final static int FRAME_bl_std29= 361;
+ public final static int FRAME_bl_std30= 362;
+ public final static int FRAME_bl_std31= 363;
+ public final static int FRAME_bl_std32= 364;
+ public final static int FRAME_bl_std33= 365;
+ public final static int FRAME_bl_std34= 366;
+ public final static int FRAME_bl_std35= 367;
+ public final static int FRAME_bl_std36= 368;
+ public final static int FRAME_bl_std37= 369;
+ public final static int FRAME_bl_std38= 370;
+ public final static int FRAME_bl_std39= 371;
+ public final static int FRAME_bl_std40= 372;
+ public final static int FRAME_bl_swm01= 373;
+ public final static int FRAME_bl_swm02= 374;
+ public final static int FRAME_bl_swm03= 375;
+ public final static int FRAME_bl_swm04= 376;
+ public final static int FRAME_bl_swm05= 377;
+ public final static int FRAME_bl_swm06= 378;
+ public final static int FRAME_bl_swm07= 379;
+ public final static int FRAME_bl_swm08= 380;
+ public final static int FRAME_bl_swm09= 381;
+ public final static int FRAME_bl_swm10= 382;
+ public final static int FRAME_bl_swm11= 383;
+ public final static int FRAME_bl_swm12= 384;
+ public final static int FRAME_bl_swk01= 385;
+ public final static int FRAME_bl_swk02= 386;
+ public final static int FRAME_bl_swk03= 387;
+ public final static int FRAME_bl_swk04= 388;
+ public final static int FRAME_bl_swk05= 389;
+ public final static int FRAME_bl_swk06= 390;
+ public final static int FRAME_bl_swp01= 391;
+ public final static int FRAME_bl_swp02= 392;
+ public final static int FRAME_bl_swp03= 393;
+ public final static int FRAME_bl_swp04= 394;
+ public final static int FRAME_bl_swp05= 395;
+ public final static int FRAME_bl_sws01= 396;
+ public final static int FRAME_bl_sws02= 397;
+ public final static int FRAME_bl_sws03= 398;
+ public final static int FRAME_bl_sws04= 399;
+ public final static int FRAME_bl_sws05= 400;
+ public final static int FRAME_bl_sws06= 401;
+ public final static int FRAME_bl_sws07= 402;
+ public final static int FRAME_bl_sws08= 403;
+ public final static int FRAME_bl_sws09= 404;
+ public final static int FRAME_bl_sws10= 405;
+ public final static int FRAME_bl_sws11= 406;
+ public final static int FRAME_bl_sws12= 407;
+ public final static int FRAME_bl_sws13= 408;
+ public final static int FRAME_bl_sws14= 409;
+ public final static int FRAME_bl_tau14= 410;
+ public final static int FRAME_bl_tau15= 411;
+ public final static int FRAME_bl_tau16= 412;
+ public final static int FRAME_bl_tau17= 413;
+ public final static int FRAME_bl_wlk01= 414;
+ public final static int FRAME_bl_wlk02= 415;
+ public final static int FRAME_bl_wlk03= 416;
+ public final static int FRAME_bl_wlk04= 417;
+ public final static int FRAME_bl_wlk05= 418;
+ public final static int FRAME_bl_wlk06= 419;
+ public final static int FRAME_bl_wlk07= 420;
+ public final static int FRAME_bl_wlk08= 421;
+ public final static int FRAME_bl_wlk09= 422;
+ public final static int FRAME_bl_wlk10= 423;
+ public final static int FRAME_bl_wlk11= 424;
+ public final static int FRAME_bl_wav19= 425;
+ public final static int FRAME_bl_wav20= 426;
+ public final static int FRAME_bl_wav21= 427;
+ public final static int FRAME_cr_atk01= 428;
+ public final static int FRAME_cr_atk02= 429;
+ public final static int FRAME_cr_atk03= 430;
+ public final static int FRAME_cr_atk04= 431;
+ public final static int FRAME_cr_atk05= 432;
+ public final static int FRAME_cr_atk06= 433;
+ public final static int FRAME_cr_atk07= 434;
+ public final static int FRAME_cr_atk08= 435;
+ public final static int FRAME_cr_pan01= 436;
+ public final static int FRAME_cr_pan02= 437;
+ public final static int FRAME_cr_pan03= 438;
+ public final static int FRAME_cr_pan04= 439;
+ public final static int FRAME_cr_std01= 440;
+ public final static int FRAME_cr_std02= 441;
+ public final static int FRAME_cr_std03= 442;
+ public final static int FRAME_cr_std04= 443;
+ public final static int FRAME_cr_std05= 444;
+ public final static int FRAME_cr_std06= 445;
+ public final static int FRAME_cr_std07= 446;
+ public final static int FRAME_cr_std08= 447;
+ public final static int FRAME_cr_wlk01= 448;
+ public final static int FRAME_cr_wlk02= 449;
+ public final static int FRAME_cr_wlk03= 450;
+ public final static int FRAME_cr_wlk04= 451;
+ public final static int FRAME_cr_wlk05= 452;
+ public final static int FRAME_cr_wlk06= 453;
+ public final static int FRAME_cr_wlk07= 454;
+ public final static int FRAME_crbl_a01= 455;
+ public final static int FRAME_crbl_a02= 456;
+ public final static int FRAME_crbl_a03= 457;
+ public final static int FRAME_crbl_a04= 458;
+ public final static int FRAME_crbl_a05= 459;
+ public final static int FRAME_crbl_a06= 460;
+ public final static int FRAME_crbl_a07= 461;
+ public final static int FRAME_crbl_p01= 462;
+ public final static int FRAME_crbl_p02= 463;
+ public final static int FRAME_crbl_p03= 464;
+ public final static int FRAME_crbl_p04= 465;
+ public final static int FRAME_crbl_s01= 466;
+ public final static int FRAME_crbl_s02= 467;
+ public final static int FRAME_crbl_s03= 468;
+ public final static int FRAME_crbl_s04= 469;
+ public final static int FRAME_crbl_s05= 470;
+ public final static int FRAME_crbl_s06= 471;
+ public final static int FRAME_crbl_s07= 472;
+ public final static int FRAME_crbl_s08= 473;
+ public final static int FRAME_crbl_w01= 474;
+ public final static int FRAME_crbl_w02= 475;
+ public final static int FRAME_crbl_w03= 476;
+ public final static int FRAME_crbl_w04= 477;
+ public final static int FRAME_crbl_w05= 478;
+ public final static int FRAME_crbl_w06= 479;
+ public final static int FRAME_crbl_w07= 480;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ public final static int MAX_ACTOR_NAMES= 8;
+
+ static String actor_names[]=
+ {
+ "Hellrot",
+ "Tokay",
+ "Killme",
+ "Disruptor",
+ "Adrianator",
+ "Rambear",
+ "Titus",
+ "Bitterman" };
+
+ static EntThinkAdapter actor_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= actor_move_stand;
+
+ // randomize on startup
+ if (level.time < 1.0)
+ self.s.frame=
+ self.monsterinfo.currentmove.firstframe
+ + (Lib.rand()
+ % (self.monsterinfo.currentmove.lastframe
+ - self.monsterinfo.currentmove.firstframe
+ + 1));
+ return true;
+ }
+ };
+
+ static mframe_t actor_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null),
+ new mframe_t(ai_stand, 0f, null)};
+
+ static mmove_t actor_move_stand=
+ new mmove_t(FRAME_stand101, FRAME_stand140, actor_frames_stand, null);
+
+ static mframe_t actor_frames_walk[]=
+ {
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 10, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 10, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null)};
+
+ static mmove_t actor_move_walk=
+ new mmove_t(FRAME_walk01, FRAME_walk08, actor_frames_walk, null);
+
+ static EntThinkAdapter actor_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= actor_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t actor_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 4, null),
+ new mframe_t(ai_run, 15, null),
+ new mframe_t(ai_run, 15, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 20, null),
+ new mframe_t(ai_run, 15, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 17, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, -2, null),
+ new mframe_t(ai_run, -2, null),
+ new mframe_t(ai_run, -1, null)};
+
+ static mmove_t actor_move_run= new mmove_t(FRAME_run02, FRAME_run07, actor_frames_run, null);
+
+ static EntThinkAdapter actor_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((level.time < self.pain_debounce_time) && (self.enemy == null)) {
+ if (self.movetarget != null)
+ actor_walk.think(self);
+ else
+ actor_stand.think(self);
+ return true;
+ }
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ actor_stand.think(self);
+ return true;
+ }
+
+ self.monsterinfo.currentmove= actor_move_run;
+ return true;
+
+ }
+ };
+
+ static mframe_t actor_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 1, null)};
+
+ static mmove_t actor_move_pain1=
+ new mmove_t(FRAME_pain101, FRAME_pain103, actor_frames_pain1, actor_run);
+
+ static mframe_t actor_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t actor_move_pain2=
+ new mmove_t(FRAME_pain201, FRAME_pain203, actor_frames_pain2, actor_run);
+
+ static mframe_t actor_frames_pain3[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t actor_move_pain3=
+ new mmove_t(FRAME_pain301, FRAME_pain303, actor_frames_pain3, actor_run);
+
+ static mframe_t actor_frames_flipoff[]=
+ new mframe_t[] {
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null)};
+
+ static mmove_t actor_move_flipoff=
+ new mmove_t(FRAME_flip01, FRAME_flip14, actor_frames_flipoff, actor_run);
+
+ static mframe_t actor_frames_taunt[]=
+ new mframe_t[] {
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null),
+ new mframe_t(ai_turn, 0, null)};
+ static mmove_t actor_move_taunt=
+ new mmove_t(FRAME_taunt01, FRAME_taunt17, actor_frames_taunt, actor_run);
+
+ static String messages[]= { "Watch it", "#$@*&", "Idiot", "Check your targets" };
+
+ static EntPainAdapter actor_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+
+ int n;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ // gi.sound (self, CHAN_VOICE, actor.sound_pain, 1, ATTN_NORM, 0);
+
+ if ((other.client != null) && (Lib.random() < 0.4)) {
+ float v[]= { 0, 0, 0 };
+
+ String name;
+
+ Math3D.VectorSubtract(other.s.origin, self.s.origin, v);
+ self.ideal_yaw= Math3D.vectoyaw(v);
+ if (Lib.random() < 0.5f)
+ self.monsterinfo.currentmove= actor_move_flipoff;
+ else
+ self.monsterinfo.currentmove= actor_move_taunt;
+
+ // FIXME: does the ent-id work out ?
+ name= actor_names[(self.index) % MAX_ACTOR_NAMES];
+
+ gi.cprintf(other, PRINT_CHAT, name + ": " + messages[Lib.rand() % 3] + "!\n");
+ return;
+ }
+
+ n= Lib.rand() % 3;
+ if (n == 0)
+ self.monsterinfo.currentmove= actor_move_pain1;
+ else if (n == 1)
+ self.monsterinfo.currentmove= actor_move_pain2;
+ else
+ self.monsterinfo.currentmove= actor_move_pain3;
+ }
+ };
+
+ static void actorMachineGun(edict_t self) {
+ float start[]= { 0, 0, 0 }, target[]= { 0, 0, 0 };
+
+ float forward[]= { 0, 0, 0 }, right[]= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_ACTOR_MACHINEGUN_1],
+ forward,
+ right,
+ start);
+
+ if (self.enemy != null) {
+ if (self.enemy.health > 0) {
+ Math3D.VectorMA(self.enemy.s.origin, -0.2f, self.enemy.velocity, target);
+ target[2] += self.enemy.viewheight;
+ } else {
+ Math3D.VectorCopy(self.enemy.absmin, target);
+ target[2] += (self.enemy.size[2] / 2);
+ }
+ Math3D.VectorSubtract(target, start, forward);
+ Math3D.VectorNormalize(forward);
+ } else {
+ Math3D.AngleVectors(self.s.angles, forward, null, null);
+ }
+ Monster.monster_fire_bullet(
+ self,
+ start,
+ forward,
+ 3,
+ 4,
+ DEFAULT_BULLET_HSPREAD,
+ DEFAULT_BULLET_VSPREAD,
+ MZ2_ACTOR_MACHINEGUN_1);
+ }
+
+ static EntThinkAdapter actor_dead= new EntThinkAdapter() {
+ public boolean actor_dead(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t actor_frames_death1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -13, null),
+ new mframe_t(ai_move, 14, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 1, null)};
+
+ static mmove_t actor_move_death1=
+ new mmove_t(FRAME_death101, FRAME_death107, actor_frames_death1, actor_dead);
+
+ static mframe_t actor_frames_death2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 7, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -9, null),
+ new mframe_t(ai_move, -13, null),
+ new mframe_t(ai_move, -13, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t actor_move_death2=
+ new mmove_t(FRAME_death201, FRAME_death213, actor_frames_death2, actor_dead);
+
+ static EntDieAdapter actor_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= -80) {
+ // gi.sound (self, CHAN_VOICE, actor.sound_gib, 1, ATTN_NORM, 0);
+ for (n= 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n= 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag= DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ // gi.sound (self, CHAN_VOICE, actor.sound_die, 1, ATTN_NORM, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_YES;
+
+ n= Lib.rand() % 2;
+ if (n == 0)
+ self.monsterinfo.currentmove= actor_move_death1;
+ else
+ self.monsterinfo.currentmove= actor_move_death2;
+ }
+ };
+
+ static EntThinkAdapter actor_fire= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ actorMachineGun(self);
+
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+
+ return true;
+ }
+ };
+
+ static mframe_t actor_frames_attack[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, -2, actor_fire),
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 2, null)};
+
+ static mmove_t actor_move_attack=
+ new mmove_t(FRAME_attak01, FRAME_attak04, actor_frames_attack, actor_run);
+
+ static EntThinkAdapter actor_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ int n;
+
+ self.monsterinfo.currentmove= actor_move_attack;
+ n= (Lib.rand() & 15) + 3 + 7;
+ self.monsterinfo.pausetime= level.time + n * FRAMETIME;
+
+ return true;
+ }
+ };
+
+ static EntUseAdapter actor_use= new EntUseAdapter() {
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ float v[]= { 0, 0, 0 };
+
+ self.goalentity= self.movetarget= G_PickTarget(self.target);
+ if ((null == self.movetarget)
+ || (Lib.strcmp(self.movetarget.classname, "target_actor") != 0)) {
+ gi.dprintf(
+ self.classname
+ + " has bad target "
+ + self.target
+ + " at "
+ + Lib.vtos(self.s.origin)
+ + "\n");
+ self.target= null;
+ self.monsterinfo.pausetime= 100000000;
+ self.monsterinfo.stand.think(self);
+ return;
+ }
+
+ Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
+ self.ideal_yaw= self.s.angles[YAW]= Math3D.vectoyaw(v);
+ self.monsterinfo.walk.think(self);
+ self.target= null;
+ }
+ };
+
+ /**
+ * QUAKED misc_actor (1 .5 0) (-16 -16 -24) (16 16 32)
+ */
+
+ static void SP_misc_actor(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ if (self.targetname != null) {
+ gi.dprintf("untargeted " + self.classname + " at " + Lib.vtos(self.s.origin) + "\n");
+ G_FreeEdict(self);
+ return;
+ }
+
+ if (self.target != null) {
+ gi.dprintf(self.classname + " with no target at " + Lib.vtos(self.s.origin) + "\n");
+ G_FreeEdict(self);
+ return;
+ }
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("players/male/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+
+ if (0 == self.health)
+ self.health= 100;
+ self.mass= 200;
+
+ self.pain= actor_pain;
+ self.die= actor_die;
+
+ self.monsterinfo.stand= actor_stand;
+ self.monsterinfo.walk= actor_walk;
+ self.monsterinfo.run= actor_run;
+ self.monsterinfo.attack= actor_attack;
+ self.monsterinfo.melee= null;
+ self.monsterinfo.sight= null;
+
+ self.monsterinfo.aiflags |= AI_GOOD_GUY;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove= actor_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ walkmonster_start.think(self);
+
+ // actors always start in a dormant state, they *must* be used to get going
+ self.use= actor_use;
+ }
+
+ /*QUAKED target_actor (.5 .3 0) (-8 -8 -8) (8 8 8) JUMP SHOOT ATTACK x HOLD BRUTAL
+ JUMP jump in set direction upon reaching this target
+ SHOOT take a single shot at the pathtarget
+ ATTACK attack pathtarget until it or actor is dead
+
+ "target" next target_actor
+ "pathtarget" target of any action to be taken at this point
+ "wait" amount of time actor should pause at this point
+ "message" actor will "say" this to the player
+
+ for JUMP only:
+ "speed" speed thrown forward (default 200)
+ "height" speed thrown upwards (default 200)
+ */
+
+ static EntTouchAdapter target_actor_touch= new EntTouchAdapter() {
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ float v[]= { 0, 0, 0 };
+
+ if (other.movetarget != self)
+ return;
+
+ if (other.enemy != null)
+ return;
+
+ other.goalentity= other.movetarget= null;
+
+ if (self.message != null) {
+ int n;
+ edict_t ent;
+
+ for (n= 1; n <= game.maxclients; n++) {
+ ent= g_edicts[n];
+ if (!ent.inuse)
+ continue;
+ gi.cprintf(
+ ent,
+ PRINT_CHAT,
+ actor_names[(other.index) % MAX_ACTOR_NAMES]
+ + ": "
+ + self.message
+ + "\n");
+ }
+ }
+
+ if ((self.spawnflags & 1) != 0) //jump
+ {
+ other.velocity[0]= self.movedir[0] * self.speed;
+ other.velocity[1]= self.movedir[1] * self.speed;
+
+ if (other.groundentity != null) {
+ other.groundentity= null;
+ other.velocity[2]= self.movedir[2];
+ gi.sound(
+ other,
+ CHAN_VOICE,
+ gi.soundindex("player/male/jump1.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ }
+ }
+
+ if ((self.spawnflags & 2) != 0) //shoot
+ {
+ } else if ((self.spawnflags & 4) != 0) //attack
+ {
+ other.enemy= G_PickTarget(self.pathtarget);
+ if (other.enemy != null) {
+ other.goalentity= other.enemy;
+ if ((self.spawnflags & 32) != 0)
+ other.monsterinfo.aiflags |= AI_BRUTAL;
+ if ((self.spawnflags & 16) != 0) {
+ other.monsterinfo.aiflags |= AI_STAND_GROUND;
+ actor_stand.think(other);
+ } else {
+ actor_run.think(other);
+ }
+ }
+ }
+
+ if (0 != (self.spawnflags & 6) && (self.pathtarget != null)) {
+ String savetarget;
+
+ savetarget= self.target;
+ self.target= self.pathtarget;
+ G_UseTargets(self, other);
+ self.target= savetarget;
+ }
+
+ other.movetarget= G_PickTarget(self.target);
+
+ if (other.goalentity == null)
+ other.goalentity= other.movetarget;
+
+ if (null == other.movetarget && null == other.enemy) {
+ other.monsterinfo.pausetime= level.time + 100000000;
+ other.monsterinfo.stand.think(other);
+ } else if (other.movetarget == other.goalentity) {
+ Math3D.VectorSubtract(other.movetarget.s.origin, other.s.origin, v);
+ other.ideal_yaw= Math3D.vectoyaw(v);
+ }
+ }
+ };
+
+ static void SP_target_actor(edict_t self) {
+ if (self.targetname != null)
+ gi.dprintf(self.classname + " with no targetname at " + Lib.vtos(self.s.origin) + " \n");
+
+ self.solid= SOLID_TRIGGER;
+ self.touch= target_actor_touch;
+ Math3D.VectorSet(self.mins, -8, -8, -8);
+ Math3D.VectorSet(self.maxs, 8, 8, 8);
+ self.svflags= SVF_NOCLIENT;
+
+ if ((self.spawnflags & 1) != 0) {
+ if (0 == self.speed)
+ self.speed= 200;
+ if (0 == st.height)
+ st.height= 200;
+ if (self.s.angles[YAW] == 0)
+ self.s.angles[YAW]= 360;
+ G_SetMovedir(self.s.angles, self.movedir);
+ self.movedir[2]= st.height;
+ }
+
+ gi.linkentity(self);
+ }
+}
diff --git a/src/jake2/game/M_Berserk.java b/src/jake2/game/M_Berserk.java
new file mode 100644
index 0000000..0998059
--- /dev/null
+++ b/src/jake2/game/M_Berserk.java
@@ -0,0 +1,724 @@
+/*
+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 11.11.2003 by RST
+// $Id: M_Berserk.java,v 1.1 2004-07-07 19:59:08 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Berserk extends GameWeapon {
+
+ public final static int FRAME_stand1= 0;
+ public final static int FRAME_stand2= 1;
+ public final static int FRAME_stand3= 2;
+ public final static int FRAME_stand4= 3;
+ public final static int FRAME_stand5= 4;
+ public final static int FRAME_standb1= 5;
+ public final static int FRAME_standb2= 6;
+ public final static int FRAME_standb3= 7;
+ public final static int FRAME_standb4= 8;
+ public final static int FRAME_standb5= 9;
+ public final static int FRAME_standb6= 10;
+ public final static int FRAME_standb7= 11;
+ public final static int FRAME_standb8= 12;
+ public final static int FRAME_standb9= 13;
+ public final static int FRAME_standb10= 14;
+ public final static int FRAME_standb11= 15;
+ public final static int FRAME_standb12= 16;
+ public final static int FRAME_standb13= 17;
+ public final static int FRAME_standb14= 18;
+ public final static int FRAME_standb15= 19;
+ public final static int FRAME_standb16= 20;
+ public final static int FRAME_standb17= 21;
+ public final static int FRAME_standb18= 22;
+ public final static int FRAME_standb19= 23;
+ public final static int FRAME_standb20= 24;
+ public final static int FRAME_walkc1= 25;
+ public final static int FRAME_walkc2= 26;
+ public final static int FRAME_walkc3= 27;
+ public final static int FRAME_walkc4= 28;
+ public final static int FRAME_walkc5= 29;
+ public final static int FRAME_walkc6= 30;
+ public final static int FRAME_walkc7= 31;
+ public final static int FRAME_walkc8= 32;
+ public final static int FRAME_walkc9= 33;
+ public final static int FRAME_walkc10= 34;
+ public final static int FRAME_walkc11= 35;
+ public final static int FRAME_run1= 36;
+ public final static int FRAME_run2= 37;
+ public final static int FRAME_run3= 38;
+ public final static int FRAME_run4= 39;
+ public final static int FRAME_run5= 40;
+ public final static int FRAME_run6= 41;
+ public final static int FRAME_att_a1= 42;
+ public final static int FRAME_att_a2= 43;
+ public final static int FRAME_att_a3= 44;
+ public final static int FRAME_att_a4= 45;
+ public final static int FRAME_att_a5= 46;
+ public final static int FRAME_att_a6= 47;
+ public final static int FRAME_att_a7= 48;
+ public final static int FRAME_att_a8= 49;
+ public final static int FRAME_att_a9= 50;
+ public final static int FRAME_att_a10= 51;
+ public final static int FRAME_att_a11= 52;
+ public final static int FRAME_att_a12= 53;
+ public final static int FRAME_att_a13= 54;
+ public final static int FRAME_att_b1= 55;
+ public final static int FRAME_att_b2= 56;
+ public final static int FRAME_att_b3= 57;
+ public final static int FRAME_att_b4= 58;
+ public final static int FRAME_att_b5= 59;
+ public final static int FRAME_att_b6= 60;
+ public final static int FRAME_att_b7= 61;
+ public final static int FRAME_att_b8= 62;
+ public final static int FRAME_att_b9= 63;
+ public final static int FRAME_att_b10= 64;
+ public final static int FRAME_att_b11= 65;
+ public final static int FRAME_att_b12= 66;
+ public final static int FRAME_att_b13= 67;
+ public final static int FRAME_att_b14= 68;
+ public final static int FRAME_att_b15= 69;
+ public final static int FRAME_att_b16= 70;
+ public final static int FRAME_att_b17= 71;
+ public final static int FRAME_att_b18= 72;
+ public final static int FRAME_att_b19= 73;
+ public final static int FRAME_att_b20= 74;
+ public final static int FRAME_att_b21= 75;
+ public final static int FRAME_att_c1= 76;
+ public final static int FRAME_att_c2= 77;
+ public final static int FRAME_att_c3= 78;
+ public final static int FRAME_att_c4= 79;
+ public final static int FRAME_att_c5= 80;
+ public final static int FRAME_att_c6= 81;
+ public final static int FRAME_att_c7= 82;
+ public final static int FRAME_att_c8= 83;
+ public final static int FRAME_att_c9= 84;
+ public final static int FRAME_att_c10= 85;
+ public final static int FRAME_att_c11= 86;
+ public final static int FRAME_att_c12= 87;
+ public final static int FRAME_att_c13= 88;
+ public final static int FRAME_att_c14= 89;
+ public final static int FRAME_att_c15= 90;
+ public final static int FRAME_att_c16= 91;
+ public final static int FRAME_att_c17= 92;
+ public final static int FRAME_att_c18= 93;
+ public final static int FRAME_att_c19= 94;
+ public final static int FRAME_att_c20= 95;
+ public final static int FRAME_att_c21= 96;
+ public final static int FRAME_att_c22= 97;
+ public final static int FRAME_att_c23= 98;
+ public final static int FRAME_att_c24= 99;
+ public final static int FRAME_att_c25= 100;
+ public final static int FRAME_att_c26= 101;
+ public final static int FRAME_att_c27= 102;
+ public final static int FRAME_att_c28= 103;
+ public final static int FRAME_att_c29= 104;
+ public final static int FRAME_att_c30= 105;
+ public final static int FRAME_att_c31= 106;
+ public final static int FRAME_att_c32= 107;
+ public final static int FRAME_att_c33= 108;
+ public final static int FRAME_att_c34= 109;
+ public final static int FRAME_r_att1= 110;
+ public final static int FRAME_r_att2= 111;
+ public final static int FRAME_r_att3= 112;
+ public final static int FRAME_r_att4= 113;
+ public final static int FRAME_r_att5= 114;
+ public final static int FRAME_r_att6= 115;
+ public final static int FRAME_r_att7= 116;
+ public final static int FRAME_r_att8= 117;
+ public final static int FRAME_r_att9= 118;
+ public final static int FRAME_r_att10= 119;
+ public final static int FRAME_r_att11= 120;
+ public final static int FRAME_r_att12= 121;
+ public final static int FRAME_r_att13= 122;
+ public final static int FRAME_r_att14= 123;
+ public final static int FRAME_r_att15= 124;
+ public final static int FRAME_r_att16= 125;
+ public final static int FRAME_r_att17= 126;
+ public final static int FRAME_r_att18= 127;
+ public final static int FRAME_r_attb1= 128;
+ public final static int FRAME_r_attb2= 129;
+ public final static int FRAME_r_attb3= 130;
+ public final static int FRAME_r_attb4= 131;
+ public final static int FRAME_r_attb5= 132;
+ public final static int FRAME_r_attb6= 133;
+ public final static int FRAME_r_attb7= 134;
+ public final static int FRAME_r_attb8= 135;
+ public final static int FRAME_r_attb9= 136;
+ public final static int FRAME_r_attb10= 137;
+ public final static int FRAME_r_attb11= 138;
+ public final static int FRAME_r_attb12= 139;
+ public final static int FRAME_r_attb13= 140;
+ public final static int FRAME_r_attb14= 141;
+ public final static int FRAME_r_attb15= 142;
+ public final static int FRAME_r_attb16= 143;
+ public final static int FRAME_r_attb17= 144;
+ public final static int FRAME_r_attb18= 145;
+ public final static int FRAME_slam1= 146;
+ public final static int FRAME_slam2= 147;
+ public final static int FRAME_slam3= 148;
+ public final static int FRAME_slam4= 149;
+ public final static int FRAME_slam5= 150;
+ public final static int FRAME_slam6= 151;
+ public final static int FRAME_slam7= 152;
+ public final static int FRAME_slam8= 153;
+ public final static int FRAME_slam9= 154;
+ public final static int FRAME_slam10= 155;
+ public final static int FRAME_slam11= 156;
+ public final static int FRAME_slam12= 157;
+ public final static int FRAME_slam13= 158;
+ public final static int FRAME_slam14= 159;
+ public final static int FRAME_slam15= 160;
+ public final static int FRAME_slam16= 161;
+ public final static int FRAME_slam17= 162;
+ public final static int FRAME_slam18= 163;
+ public final static int FRAME_slam19= 164;
+ public final static int FRAME_slam20= 165;
+ public final static int FRAME_slam21= 166;
+ public final static int FRAME_slam22= 167;
+ public final static int FRAME_slam23= 168;
+ public final static int FRAME_duck1= 169;
+ public final static int FRAME_duck2= 170;
+ public final static int FRAME_duck3= 171;
+ public final static int FRAME_duck4= 172;
+ public final static int FRAME_duck5= 173;
+ public final static int FRAME_duck6= 174;
+ public final static int FRAME_duck7= 175;
+ public final static int FRAME_duck8= 176;
+ public final static int FRAME_duck9= 177;
+ public final static int FRAME_duck10= 178;
+ public final static int FRAME_fall1= 179;
+ public final static int FRAME_fall2= 180;
+ public final static int FRAME_fall3= 181;
+ public final static int FRAME_fall4= 182;
+ public final static int FRAME_fall5= 183;
+ public final static int FRAME_fall6= 184;
+ public final static int FRAME_fall7= 185;
+ public final static int FRAME_fall8= 186;
+ public final static int FRAME_fall9= 187;
+ public final static int FRAME_fall10= 188;
+ public final static int FRAME_fall11= 189;
+ public final static int FRAME_fall12= 190;
+ public final static int FRAME_fall13= 191;
+ public final static int FRAME_fall14= 192;
+ public final static int FRAME_fall15= 193;
+ public final static int FRAME_fall16= 194;
+ public final static int FRAME_fall17= 195;
+ public final static int FRAME_fall18= 196;
+ public final static int FRAME_fall19= 197;
+ public final static int FRAME_fall20= 198;
+ public final static int FRAME_painc1= 199;
+ public final static int FRAME_painc2= 200;
+ public final static int FRAME_painc3= 201;
+ public final static int FRAME_painc4= 202;
+ public final static int FRAME_painb1= 203;
+ public final static int FRAME_painb2= 204;
+ public final static int FRAME_painb3= 205;
+ public final static int FRAME_painb4= 206;
+ public final static int FRAME_painb5= 207;
+ public final static int FRAME_painb6= 208;
+ public final static int FRAME_painb7= 209;
+ public final static int FRAME_painb8= 210;
+ public final static int FRAME_painb9= 211;
+ public final static int FRAME_painb10= 212;
+ public final static int FRAME_painb11= 213;
+ public final static int FRAME_painb12= 214;
+ public final static int FRAME_painb13= 215;
+ public final static int FRAME_painb14= 216;
+ public final static int FRAME_painb15= 217;
+ public final static int FRAME_painb16= 218;
+ public final static int FRAME_painb17= 219;
+ public final static int FRAME_painb18= 220;
+ public final static int FRAME_painb19= 221;
+ public final static int FRAME_painb20= 222;
+ public final static int FRAME_death1= 223;
+ public final static int FRAME_death2= 224;
+ public final static int FRAME_death3= 225;
+ public final static int FRAME_death4= 226;
+ public final static int FRAME_death5= 227;
+ public final static int FRAME_death6= 228;
+ public final static int FRAME_death7= 229;
+ public final static int FRAME_death8= 230;
+ public final static int FRAME_death9= 231;
+ public final static int FRAME_death10= 232;
+ public final static int FRAME_death11= 233;
+ public final static int FRAME_death12= 234;
+ public final static int FRAME_death13= 235;
+ public final static int FRAME_deathc1= 236;
+ public final static int FRAME_deathc2= 237;
+ public final static int FRAME_deathc3= 238;
+ public final static int FRAME_deathc4= 239;
+ public final static int FRAME_deathc5= 240;
+ public final static int FRAME_deathc6= 241;
+ public final static int FRAME_deathc7= 242;
+ public final static int FRAME_deathc8= 243;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_pain;
+ static int sound_die;
+ static int sound_idle;
+ static int sound_punch;
+ static int sound_sight;
+ static int sound_search;
+
+ static EntInteractAdapter berserk_sight= new EntInteractAdapter() {
+ public void interact(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ }
+ };
+
+ static EntThinkAdapter berserk_search= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter berserk_fidget= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ return true;
+
+ if (Lib.random() > 0.15f)
+ return true;
+
+ self.monsterinfo.currentmove= berserk_move_stand_fidget;
+ gi.sound(self, CHAN_WEAPON, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static mframe_t berserk_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, berserk_fidget),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+
+ static mmove_t berserk_move_stand=
+ new mmove_t(FRAME_stand1, FRAME_stand5, berserk_frames_stand, null);
+
+ static EntThinkAdapter berserk_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= berserk_move_stand;
+ return true;
+ }
+ };
+
+ static mframe_t berserk_frames_stand_fidget[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+
+ static mmove_t berserk_move_stand_fidget=
+ new mmove_t(FRAME_standb1, FRAME_standb20, berserk_frames_stand_fidget, berserk_stand);
+
+ static mframe_t berserk_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 9.1f, null),
+ new mframe_t(ai_walk, 6.3f, null),
+ new mframe_t(ai_walk, 4.9f, null),
+ new mframe_t(ai_walk, 6.7f, null),
+ new mframe_t(ai_walk, 6.0f, null),
+ new mframe_t(ai_walk, 8.2f, null),
+ new mframe_t(ai_walk, 7.2f, null),
+ new mframe_t(ai_walk, 6.1f, null),
+ new mframe_t(ai_walk, 4.9f, null),
+ new mframe_t(ai_walk, 4.7f, null),
+ new mframe_t(ai_walk, 4.7f, null),
+ new mframe_t(ai_walk, 4.8f, null)};
+
+ static mmove_t berserk_move_walk=
+ new mmove_t(FRAME_walkc1, FRAME_walkc11, berserk_frames_walk, null);
+
+ static EntThinkAdapter berserk_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= berserk_move_walk;
+ return true;
+ }
+ };
+
+ /*
+
+ *****************************
+ SKIPPED THIS FOR NOW!
+ *****************************
+
+ Running . Arm raised in air
+
+ void() berserk_runb1 =[ $r_att1 , berserk_runb2 ] {ai_run(21);};
+ void() berserk_runb2 =[ $r_att2 , berserk_runb3 ] {ai_run(11);};
+ void() berserk_runb3 =[ $r_att3 , berserk_runb4 ] {ai_run(21);};
+ void() berserk_runb4 =[ $r_att4 , berserk_runb5 ] {ai_run(25);};
+ void() berserk_runb5 =[ $r_att5 , berserk_runb6 ] {ai_run(18);};
+ void() berserk_runb6 =[ $r_att6 , berserk_runb7 ] {ai_run(19);};
+ // running with arm in air : start loop
+ void() berserk_runb7 =[ $r_att7 , berserk_runb8 ] {ai_run(21);};
+ void() berserk_runb8 =[ $r_att8 , berserk_runb9 ] {ai_run(11);};
+ void() berserk_runb9 =[ $r_att9 , berserk_runb10 ] {ai_run(21);};
+ void() berserk_runb10 =[ $r_att10 , berserk_runb11 ] {ai_run(25);};
+ void() berserk_runb11 =[ $r_att11 , berserk_runb12 ] {ai_run(18);};
+ void() berserk_runb12 =[ $r_att12 , berserk_runb7 ] {ai_run(19);};
+ // running with arm in air : end loop
+ */
+
+ static mframe_t berserk_frames_run1[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 21, null),
+ new mframe_t(ai_run, 11, null),
+ new mframe_t(ai_run, 21, null),
+ new mframe_t(ai_run, 25, null),
+ new mframe_t(ai_run, 18, null),
+ new mframe_t(ai_run, 19, null)};
+ static mmove_t berserk_move_run1=
+ new mmove_t(FRAME_run1, FRAME_run6, berserk_frames_run1, null);
+
+ static EntThinkAdapter berserk_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove= berserk_move_stand;
+ else
+ self.monsterinfo.currentmove= berserk_move_run1;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter berserk_attack_spike= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim= { MELEE_DISTANCE, 0f, -24f };
+
+ Fire.fire_hit(self, aim, (15 + (Lib.rand() % 6)), 400);
+ // Faster attack -- upwards and backwards
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter berserk_swing= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_punch, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t berserk_frames_attack_spike[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, berserk_swing),
+ new mframe_t(ai_charge, 0, berserk_attack_spike),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+
+ static mmove_t berserk_move_attack_spike=
+ new mmove_t(FRAME_att_c1, FRAME_att_c8, berserk_frames_attack_spike, berserk_run);
+ static EntThinkAdapter berserk_attack_club= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float aim[]= { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.mins[0], -4);
+ Fire.fire_hit(self, aim, (5 + (Lib.rand() % 6)), 400); // Slower attack
+
+ return true;
+ }
+ };
+
+ static mframe_t berserk_frames_attack_club[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, berserk_swing),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, berserk_attack_club),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t berserk_move_attack_club=
+ new mmove_t(FRAME_att_c9, FRAME_att_c20, berserk_frames_attack_club, berserk_run);
+
+ static EntThinkAdapter berserk_strike= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ return true;
+ }
+ };
+
+ static mframe_t berserk_frames_attack_strike[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, berserk_swing),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, berserk_strike),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 9.7f, null),
+ new mframe_t(ai_move, 13.6f, null)};
+
+ static mmove_t berserk_move_attack_strike=
+ new mmove_t(FRAME_att_c21, FRAME_att_c34, berserk_frames_attack_strike, berserk_run);
+
+ static EntThinkAdapter berserk_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((Lib.rand() % 2) == 0)
+ self.monsterinfo.currentmove= berserk_move_attack_spike;
+ else
+ self.monsterinfo.currentmove= berserk_move_attack_club;
+ return true;
+ }
+ };
+
+ /*
+ void() berserk_atke1 =[ $r_attb1, berserk_atke2 ] {ai_run(9);};
+ void() berserk_atke2 =[ $r_attb2, berserk_atke3 ] {ai_run(6);};
+ void() berserk_atke3 =[ $r_attb3, berserk_atke4 ] {ai_run(18.4);};
+ void() berserk_atke4 =[ $r_attb4, berserk_atke5 ] {ai_run(25);};
+ void() berserk_atke5 =[ $r_attb5, berserk_atke6 ] {ai_run(14);};
+ void() berserk_atke6 =[ $r_attb6, berserk_atke7 ] {ai_run(20);};
+ void() berserk_atke7 =[ $r_attb7, berserk_atke8 ] {ai_run(8.5);};
+ void() berserk_atke8 =[ $r_attb8, berserk_atke9 ] {ai_run(3);};
+ void() berserk_atke9 =[ $r_attb9, berserk_atke10 ] {ai_run(17.5);};
+ void() berserk_atke10 =[ $r_attb10, berserk_atke11 ] {ai_run(17);};
+ void() berserk_atke11 =[ $r_attb11, berserk_atke12 ] {ai_run(9);};
+ void() berserk_atke12 =[ $r_attb12, berserk_atke13 ] {ai_run(25);};
+ void() berserk_atke13 =[ $r_attb13, berserk_atke14 ] {ai_run(3.7);};
+ void() berserk_atke14 =[ $r_attb14, berserk_atke15 ] {ai_run(2.6);};
+ void() berserk_atke15 =[ $r_attb15, berserk_atke16 ] {ai_run(19);};
+ void() berserk_atke16 =[ $r_attb16, berserk_atke17 ] {ai_run(25);};
+ void() berserk_atke17 =[ $r_attb17, berserk_atke18 ] {ai_run(19.6);};
+ void() berserk_atke18 =[ $r_attb18, berserk_run1 ] {ai_run(7.8);};
+ */
+
+ static mframe_t berserk_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t berserk_move_pain1=
+ new mmove_t(FRAME_painc1, FRAME_painc4, berserk_frames_pain1, berserk_run);
+
+ static mframe_t berserk_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t berserk_move_pain2=
+ new mmove_t(FRAME_painb1, FRAME_painb20, berserk_frames_pain2, berserk_run);
+
+ static EntPainAdapter berserk_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ gi.sound(self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if ((damage < 20) || (Lib.random() < 0.5))
+ self.monsterinfo.currentmove= berserk_move_pain1;
+ else
+ self.monsterinfo.currentmove= berserk_move_pain2;
+ }
+ };
+
+ static EntThinkAdapter berserk_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t berserk_frames_death1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t berserk_move_death1=
+ new mmove_t(FRAME_death1, FRAME_death13, berserk_frames_death1, berserk_dead);
+
+ static mframe_t berserk_frames_death2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t berserk_move_death2=
+ new mmove_t(FRAME_deathc1, FRAME_deathc8, berserk_frames_death2, berserk_dead);
+
+ static EntDieAdapter berserk_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float point) {
+ int n;
+
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n= 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n= 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag= DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_YES;
+
+ if (damage >= 50)
+ self.monsterinfo.currentmove= berserk_move_death1;
+ else
+ self.monsterinfo.currentmove= berserk_move_death2;
+ }
+ };
+
+ /*
+ * QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_berserk(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ // pre-caches
+ sound_pain= gi.soundindex("berserk/berpain2.wav");
+ sound_die= gi.soundindex("berserk/berdeth2.wav");
+ sound_idle= gi.soundindex("berserk/beridle1.wav");
+ sound_punch= gi.soundindex("berserk/attack.wav");
+ sound_search= gi.soundindex("berserk/bersrch1.wav");
+ sound_sight= gi.soundindex("berserk/sight.wav");
+
+ self.s.modelindex= gi.modelindex("models/monsters/berserk/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+
+ self.health= 240;
+ self.gib_health= -60;
+ self.mass= 250;
+
+ self.pain= berserk_pain;
+ self.die= berserk_die;
+
+ self.monsterinfo.stand= berserk_stand;
+ self.monsterinfo.walk= berserk_walk;
+ self.monsterinfo.run= berserk_run;
+ self.monsterinfo.dodge= null;
+ self.monsterinfo.attack= null;
+ self.monsterinfo.melee= berserk_melee;
+ self.monsterinfo.sight= berserk_sight;
+ self.monsterinfo.search= berserk_search;
+
+ self.monsterinfo.currentmove= berserk_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ gi.linkentity(self);
+
+ walkmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Boss2.java b/src/jake2/game/M_Boss2.java
new file mode 100644
index 0000000..735a370
--- /dev/null
+++ b/src/jake2/game/M_Boss2.java
@@ -0,0 +1,899 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Boss2.java,v 1.1 2004-07-07 19:59:09 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Boss2 extends GameWeapon {
+
+ public final static int FRAME_stand30= 0;
+ public final static int FRAME_stand31= 1;
+ public final static int FRAME_stand32= 2;
+ public final static int FRAME_stand33= 3;
+ public final static int FRAME_stand34= 4;
+ public final static int FRAME_stand35= 5;
+ public final static int FRAME_stand36= 6;
+ public final static int FRAME_stand37= 7;
+ public final static int FRAME_stand38= 8;
+ public final static int FRAME_stand39= 9;
+ public final static int FRAME_stand40= 10;
+ public final static int FRAME_stand41= 11;
+ public final static int FRAME_stand42= 12;
+ public final static int FRAME_stand43= 13;
+ public final static int FRAME_stand44= 14;
+ public final static int FRAME_stand45= 15;
+ public final static int FRAME_stand46= 16;
+ public final static int FRAME_stand47= 17;
+ public final static int FRAME_stand48= 18;
+ public final static int FRAME_stand49= 19;
+ public final static int FRAME_stand50= 20;
+ public final static int FRAME_stand1= 21;
+ public final static int FRAME_stand2= 22;
+ public final static int FRAME_stand3= 23;
+ public final static int FRAME_stand4= 24;
+ public final static int FRAME_stand5= 25;
+ public final static int FRAME_stand6= 26;
+ public final static int FRAME_stand7= 27;
+ public final static int FRAME_stand8= 28;
+ public final static int FRAME_stand9= 29;
+ public final static int FRAME_stand10= 30;
+ public final static int FRAME_stand11= 31;
+ public final static int FRAME_stand12= 32;
+ public final static int FRAME_stand13= 33;
+ public final static int FRAME_stand14= 34;
+ public final static int FRAME_stand15= 35;
+ public final static int FRAME_stand16= 36;
+ public final static int FRAME_stand17= 37;
+ public final static int FRAME_stand18= 38;
+ public final static int FRAME_stand19= 39;
+ public final static int FRAME_stand20= 40;
+ public final static int FRAME_stand21= 41;
+ public final static int FRAME_stand22= 42;
+ public final static int FRAME_stand23= 43;
+ public final static int FRAME_stand24= 44;
+ public final static int FRAME_stand25= 45;
+ public final static int FRAME_stand26= 46;
+ public final static int FRAME_stand27= 47;
+ public final static int FRAME_stand28= 48;
+ public final static int FRAME_stand29= 49;
+ public final static int FRAME_walk1= 50;
+ public final static int FRAME_walk2= 51;
+ public final static int FRAME_walk3= 52;
+ public final static int FRAME_walk4= 53;
+ public final static int FRAME_walk5= 54;
+ public final static int FRAME_walk6= 55;
+ public final static int FRAME_walk7= 56;
+ public final static int FRAME_walk8= 57;
+ public final static int FRAME_walk9= 58;
+ public final static int FRAME_walk10= 59;
+ public final static int FRAME_walk11= 60;
+ public final static int FRAME_walk12= 61;
+ public final static int FRAME_walk13= 62;
+ public final static int FRAME_walk14= 63;
+ public final static int FRAME_walk15= 64;
+ public final static int FRAME_walk16= 65;
+ public final static int FRAME_walk17= 66;
+ public final static int FRAME_walk18= 67;
+ public final static int FRAME_walk19= 68;
+ public final static int FRAME_walk20= 69;
+ public final static int FRAME_attack1= 70;
+ public final static int FRAME_attack2= 71;
+ public final static int FRAME_attack3= 72;
+ public final static int FRAME_attack4= 73;
+ public final static int FRAME_attack5= 74;
+ public final static int FRAME_attack6= 75;
+ public final static int FRAME_attack7= 76;
+ public final static int FRAME_attack8= 77;
+ public final static int FRAME_attack9= 78;
+ public final static int FRAME_attack10= 79;
+ public final static int FRAME_attack11= 80;
+ public final static int FRAME_attack12= 81;
+ public final static int FRAME_attack13= 82;
+ public final static int FRAME_attack14= 83;
+ public final static int FRAME_attack15= 84;
+ public final static int FRAME_attack16= 85;
+ public final static int FRAME_attack17= 86;
+ public final static int FRAME_attack18= 87;
+ public final static int FRAME_attack19= 88;
+ public final static int FRAME_attack20= 89;
+ public final static int FRAME_attack21= 90;
+ public final static int FRAME_attack22= 91;
+ public final static int FRAME_attack23= 92;
+ public final static int FRAME_attack24= 93;
+ public final static int FRAME_attack25= 94;
+ public final static int FRAME_attack26= 95;
+ public final static int FRAME_attack27= 96;
+ public final static int FRAME_attack28= 97;
+ public final static int FRAME_attack29= 98;
+ public final static int FRAME_attack30= 99;
+ public final static int FRAME_attack31= 100;
+ public final static int FRAME_attack32= 101;
+ public final static int FRAME_attack33= 102;
+ public final static int FRAME_attack34= 103;
+ public final static int FRAME_attack35= 104;
+ public final static int FRAME_attack36= 105;
+ public final static int FRAME_attack37= 106;
+ public final static int FRAME_attack38= 107;
+ public final static int FRAME_attack39= 108;
+ public final static int FRAME_attack40= 109;
+ public final static int FRAME_pain2= 110;
+ public final static int FRAME_pain3= 111;
+ public final static int FRAME_pain4= 112;
+ public final static int FRAME_pain5= 113;
+ public final static int FRAME_pain6= 114;
+ public final static int FRAME_pain7= 115;
+ public final static int FRAME_pain8= 116;
+ public final static int FRAME_pain9= 117;
+ public final static int FRAME_pain10= 118;
+ public final static int FRAME_pain11= 119;
+ public final static int FRAME_pain12= 120;
+ public final static int FRAME_pain13= 121;
+ public final static int FRAME_pain14= 122;
+ public final static int FRAME_pain15= 123;
+ public final static int FRAME_pain16= 124;
+ public final static int FRAME_pain17= 125;
+ public final static int FRAME_pain18= 126;
+ public final static int FRAME_pain19= 127;
+ public final static int FRAME_pain20= 128;
+ public final static int FRAME_pain21= 129;
+ public final static int FRAME_pain22= 130;
+ public final static int FRAME_pain23= 131;
+ public final static int FRAME_death2= 132;
+ public final static int FRAME_death3= 133;
+ public final static int FRAME_death4= 134;
+ public final static int FRAME_death5= 135;
+ public final static int FRAME_death6= 136;
+ public final static int FRAME_death7= 137;
+ public final static int FRAME_death8= 138;
+ public final static int FRAME_death9= 139;
+ public final static int FRAME_death10= 140;
+ public final static int FRAME_death11= 141;
+ public final static int FRAME_death12= 142;
+ public final static int FRAME_death13= 143;
+ public final static int FRAME_death14= 144;
+ public final static int FRAME_death15= 145;
+ public final static int FRAME_death16= 146;
+ public final static int FRAME_death17= 147;
+ public final static int FRAME_death18= 148;
+ public final static int FRAME_death19= 149;
+ public final static int FRAME_death20= 150;
+ public final static int FRAME_death21= 151;
+ public final static int FRAME_death22= 152;
+ public final static int FRAME_death23= 153;
+ public final static int FRAME_death24= 154;
+ public final static int FRAME_death25= 155;
+ public final static int FRAME_death26= 156;
+ public final static int FRAME_death27= 157;
+ public final static int FRAME_death28= 158;
+ public final static int FRAME_death29= 159;
+ public final static int FRAME_death30= 160;
+ public final static int FRAME_death31= 161;
+ public final static int FRAME_death32= 162;
+ public final static int FRAME_death33= 163;
+ public final static int FRAME_death34= 164;
+ public final static int FRAME_death35= 165;
+ public final static int FRAME_death36= 166;
+ public final static int FRAME_death37= 167;
+ public final static int FRAME_death38= 168;
+ public final static int FRAME_death39= 169;
+ public final static int FRAME_death40= 170;
+ public final static int FRAME_death41= 171;
+ public final static int FRAME_death42= 172;
+ public final static int FRAME_death43= 173;
+ public final static int FRAME_death44= 174;
+ public final static int FRAME_death45= 175;
+ public final static int FRAME_death46= 176;
+ public final static int FRAME_death47= 177;
+ public final static int FRAME_death48= 178;
+ public final static int FRAME_death49= 179;
+ public final static int FRAME_death50= 180;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_pain3;
+ static int sound_death;
+ static int sound_search1;
+
+ static EntThinkAdapter boss2_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= boss2_move_stand;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter boss2_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove= boss2_move_stand;
+ else
+ self.monsterinfo.currentmove= boss2_move_run;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter boss2_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= boss2_move_stand;
+
+ self.monsterinfo.currentmove= boss2_move_walk;
+ return true;
+ }
+ };
+ static EntThinkAdapter boss2_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] vec= { 0, 0, 0 };
+
+ float range;
+
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, vec);
+ range= Math3D.VectorLength(vec);
+
+ if (range <= 125) {
+ self.monsterinfo.currentmove= boss2_move_attack_pre_mg;
+ } else {
+ if (Lib.random() <= 0.6)
+ self.monsterinfo.currentmove= boss2_move_attack_pre_mg;
+ else
+ self.monsterinfo.currentmove= boss2_move_attack_rocket;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter boss2_attack_mg= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= boss2_move_attack_mg;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter boss2_reattack_mg= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (infront(self, self.enemy))
+ if (Lib.random() <= 0.7)
+ self.monsterinfo.currentmove= boss2_move_attack_mg;
+ else
+ self.monsterinfo.currentmove= boss2_move_attack_post_mg;
+ else
+ self.monsterinfo.currentmove= boss2_move_attack_post_mg;
+ return true;
+ }
+ };
+
+ static EntPainAdapter boss2_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ // American wanted these at no attenuation
+ if (damage < 10) {
+ gi.sound(self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0);
+ self.monsterinfo.currentmove= boss2_move_pain_light;
+ } else if (damage < 30) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0);
+ self.monsterinfo.currentmove= boss2_move_pain_light;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0);
+ self.monsterinfo.currentmove= boss2_move_pain_heavy;
+ }
+ }
+ };
+
+ static EntThinkAdapter boss2_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -56, -56, 0);
+ Math3D.VectorSet(self.maxs, 56, 56, 80);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntDieAdapter boss2_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_NO;
+ self.count= 0;
+ self.monsterinfo.currentmove= boss2_move_death;
+
+ }
+ };
+
+ static EntThinkAdapter Boss2_CheckAttack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] spot1= { 0, 0, 0 }, spot2= { 0, 0, 0 };
+ float[] temp= { 0, 0, 0 };
+ float chance;
+ trace_t tr;
+ boolean enemy_infront;
+ int enemy_range;
+ float enemy_yaw;
+
+ if (self.enemy.health > 0) {
+ // see if any entities are in the way of the shot
+ Math3D.VectorCopy(self.s.origin, spot1);
+ spot1[2] += self.viewheight;
+ Math3D.VectorCopy(self.enemy.s.origin, spot2);
+ spot2[2] += self.enemy.viewheight;
+
+ tr=
+ gi.trace(
+ spot1,
+ null,
+ null,
+ spot2,
+ self,
+ CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA);
+
+ // do we have a clear shot?
+ if (tr.ent != self.enemy)
+ return false;
+ }
+
+ enemy_infront= infront(self, self.enemy);
+ enemy_range= range(self, self.enemy);
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp);
+ enemy_yaw= Math3D.vectoyaw(temp);
+
+ self.ideal_yaw= enemy_yaw;
+
+ // melee attack
+ if (enemy_range == RANGE_MELEE) {
+ if (self.monsterinfo.melee != null)
+ self.monsterinfo.attack_state= AS_MELEE;
+ else
+ self.monsterinfo.attack_state= AS_MISSILE;
+ return true;
+ }
+
+ // missile attack
+ if (self.monsterinfo.attack == null)
+ return false;
+
+ if (level.time < self.monsterinfo.attack_finished)
+ return false;
+
+ if (enemy_range == RANGE_FAR)
+ return false;
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ chance= 0.4f;
+ } else if (enemy_range == RANGE_MELEE) {
+ chance= 0.8f;
+ } else if (enemy_range == RANGE_NEAR) {
+ chance= 0.8f;
+ } else if (enemy_range == RANGE_MID) {
+ chance= 0.8f;
+ } else {
+ return false;
+ }
+
+ if (Lib.random() < chance) {
+ self.monsterinfo.attack_state= AS_MISSILE;
+ self.monsterinfo.attack_finished= level.time + 2 * Lib.random();
+ return true;
+ }
+
+ if ((self.flags & FL_FLY) != 0) {
+ if (Lib.random() < 0.3)
+ self.monsterinfo.attack_state= AS_SLIDING;
+ else
+ self.monsterinfo.attack_state= AS_STRAIGHT;
+ }
+
+ return false;
+ }
+ };
+
+ static EntThinkAdapter boss2_search= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Boss2Rocket= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+ float[] dir= { 0, 0, 0 };
+ float[] vec= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+
+ // 1
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_BOSS2_ROCKET_1],
+ forward,
+ right,
+ start);
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+ Monster.monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_1);
+
+ // 2
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_BOSS2_ROCKET_2],
+ forward,
+ right,
+ start);
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+ Monster.monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
+
+ // 3
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_BOSS2_ROCKET_3],
+ forward,
+ right,
+ start);
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+ Monster.monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_3);
+
+ // 4
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_BOSS2_ROCKET_4],
+ forward,
+ right,
+ start);
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+ Monster.monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter boss2_firebullet_right= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, target= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_BOSS2_MACHINEGUN_R1],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorMA(self.enemy.s.origin, -0.2f, self.enemy.velocity, target);
+ target[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(target, start, forward);
+ Math3D.VectorNormalize(forward);
+
+ Monster.monster_fire_bullet(
+ self,
+ start,
+ forward,
+ 6,
+ 4,
+ DEFAULT_BULLET_HSPREAD,
+ DEFAULT_BULLET_VSPREAD,
+ MZ2_BOSS2_MACHINEGUN_R1);
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter boss2_firebullet_left= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, target= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_BOSS2_MACHINEGUN_L1],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorMA(self.enemy.s.origin, -0.2f, self.enemy.velocity, target);
+
+ target[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(target, start, forward);
+ Math3D.VectorNormalize(forward);
+
+ Monster.monster_fire_bullet(
+ self,
+ start,
+ forward,
+ 6,
+ 4,
+ DEFAULT_BULLET_HSPREAD,
+ DEFAULT_BULLET_VSPREAD,
+ MZ2_BOSS2_MACHINEGUN_L1);
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Boss2MachineGun= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ /*
+ * RST: this was disabled !
+ * float[] forward={0,0,0}, right={0,0,0};
+ float[] start={0,0,0};
+ float[] dir={0,0,0};
+ float[] vec={0,0,0};
+ int flash_number;
+
+ AngleVectors (self.s.angles, forward, right, null);
+
+ flash_number = MZ2_BOSS2_MACHINEGUN_1 + (self.s.frame - FRAME_attack10);
+ G_ProjectSource (self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ VectorCopy (self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ VectorSubtract (vec, start, dir);
+ VectorNormalize (dir);
+ monster_fire_bullet (self, start, dir, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+ */
+ boss2_firebullet_left.think(self);
+ boss2_firebullet_right.think(self);
+ return true;
+ }
+ };
+
+ static mframe_t boss2_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t boss2_move_stand=
+ new mmove_t(FRAME_stand30, FRAME_stand50, boss2_frames_stand, null);
+
+ static mframe_t boss2_frames_fidget[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t boss2_move_fidget=
+ new mmove_t(FRAME_stand1, FRAME_stand30, boss2_frames_fidget, null);
+
+ static mframe_t boss2_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null)};
+ static mmove_t boss2_move_walk= new mmove_t(FRAME_walk1, FRAME_walk20, boss2_frames_walk, null);
+
+ static mframe_t boss2_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null)};
+ static mmove_t boss2_move_run= new mmove_t(FRAME_walk1, FRAME_walk20, boss2_frames_run, null);
+
+ static mframe_t boss2_frames_attack_pre_mg[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, boss2_attack_mg)};
+ static mmove_t boss2_move_attack_pre_mg=
+ new mmove_t(FRAME_attack1, FRAME_attack9, boss2_frames_attack_pre_mg, null);
+
+ // Loop this
+ static mframe_t boss2_frames_attack_mg[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 1, Boss2MachineGun),
+ new mframe_t(ai_charge, 1, Boss2MachineGun),
+ new mframe_t(ai_charge, 1, Boss2MachineGun),
+ new mframe_t(ai_charge, 1, Boss2MachineGun),
+ new mframe_t(ai_charge, 1, Boss2MachineGun),
+ new mframe_t(ai_charge, 1, boss2_reattack_mg)};
+ static mmove_t boss2_move_attack_mg=
+ new mmove_t(FRAME_attack10, FRAME_attack15, boss2_frames_attack_mg, null);
+
+ static mframe_t boss2_frames_attack_post_mg[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null)};
+ static mmove_t boss2_move_attack_post_mg=
+ new mmove_t(FRAME_attack16, FRAME_attack19, boss2_frames_attack_post_mg, boss2_run);
+
+ static mframe_t boss2_frames_attack_rocket[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_move, -20, Boss2Rocket),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null)};
+ static mmove_t boss2_move_attack_rocket=
+ new mmove_t(FRAME_attack20, FRAME_attack40, boss2_frames_attack_rocket, boss2_run);
+
+ static mframe_t boss2_frames_pain_heavy[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t boss2_move_pain_heavy=
+ new mmove_t(FRAME_pain2, FRAME_pain19, boss2_frames_pain_heavy, boss2_run);
+
+ static mframe_t boss2_frames_pain_light[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t boss2_move_pain_light=
+ new mmove_t(FRAME_pain20, FRAME_pain23, boss2_frames_pain_light, boss2_run);
+
+ static mframe_t boss2_frames_death[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, BossExplode)};
+
+ /*
+ static EntThinkAdapter xxx = new EntThinkAdapter()
+ {
+ public boolean think(edict_t self)
+ {
+ return true;
+ }
+ };
+ */
+
+ static mmove_t boss2_move_death=
+ new mmove_t(FRAME_death2, FRAME_death50, boss2_frames_death, boss2_dead);
+
+ /*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_boss2(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_pain1= gi.soundindex("bosshovr/bhvpain1.wav");
+ sound_pain2= gi.soundindex("bosshovr/bhvpain2.wav");
+ sound_pain3= gi.soundindex("bosshovr/bhvpain3.wav");
+ sound_death= gi.soundindex("bosshovr/bhvdeth1.wav");
+ sound_search1= gi.soundindex("bosshovr/bhvunqv1.wav");
+
+ self.s.sound= gi.soundindex("bosshovr/bhvengn1.wav");
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/boss2/tris.md2");
+ Math3D.VectorSet(self.mins, -56, -56, 0);
+ Math3D.VectorSet(self.maxs, 56, 56, 80);
+
+ self.health= 2000;
+ self.gib_health= -200;
+ self.mass= 1000;
+
+ self.flags |= FL_IMMUNE_LASER;
+
+ self.pain= boss2_pain;
+ self.die= boss2_die;
+
+ self.monsterinfo.stand= boss2_stand;
+ self.monsterinfo.walk= boss2_walk;
+ self.monsterinfo.run= boss2_run;
+ self.monsterinfo.attack= boss2_attack;
+ self.monsterinfo.search= boss2_search;
+ self.monsterinfo.checkattack= Boss2_CheckAttack;
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove= boss2_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ flymonster_start.think(self);
+ }
+}
diff --git a/src/jake2/game/M_Boss3.java b/src/jake2/game/M_Boss3.java
new file mode 100644
index 0000000..ca41173
--- /dev/null
+++ b/src/jake2/game/M_Boss3.java
@@ -0,0 +1,76 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Boss3.java,v 1.1 2004-07-07 19:59:09 hzi Exp $
+
+package jake2.game;
+
+public class M_Boss3 extends M_Boss32 {
+
+ static EntUseAdapter Use_Boss3 = new EntUseAdapter() {
+ public void use(edict_t ent, edict_t other, edict_t activator) {
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_BOSSTPORT);
+ gi.WritePosition(ent.s.origin);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+ G_FreeEdict(ent);
+ }
+ };
+
+ static EntThinkAdapter Think_Boss3Stand = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ if (ent.s.frame == FRAME_stand260)
+ ent.s.frame = FRAME_stand201;
+ else
+ ent.s.frame++;
+ ent.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+
+ };
+
+ /*QUAKED monster_boss3_stand (1 .5 0) (-32 -32 0) (32 32 90)
+
+ Just stands and cycles in one place until targeted, then teleports away.
+ */
+ static void SP_monster_boss3_stand(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.model = "models/monsters/boss3/rider/tris.md2";
+ self.s.modelindex = gi.modelindex(self.model);
+ self.s.frame = FRAME_stand201;
+
+ gi.soundindex("misc/bigtele.wav");
+
+ VectorSet(self.mins, -32, -32, 0);
+ VectorSet(self.maxs, 32, 32, 90);
+
+ self.use = Use_Boss3;
+ self.think = Think_Boss3Stand;
+ self.nextthink = level.time + FRAMETIME;
+ gi.linkentity(self);
+ }
+}
diff --git a/src/jake2/game/M_Boss31.java b/src/jake2/game/M_Boss31.java
new file mode 100644
index 0000000..7350c3b
--- /dev/null
+++ b/src/jake2/game/M_Boss31.java
@@ -0,0 +1,1012 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Boss31.java,v 1.1 2004-07-07 19:59:09 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Boss31 extends GameWeapon {
+
+ public final static int FRAME_attak101= 0;
+ public final static int FRAME_attak102= 1;
+ public final static int FRAME_attak103= 2;
+ public final static int FRAME_attak104= 3;
+ public final static int FRAME_attak105= 4;
+ public final static int FRAME_attak106= 5;
+ public final static int FRAME_attak107= 6;
+ public final static int FRAME_attak108= 7;
+ public final static int FRAME_attak109= 8;
+ public final static int FRAME_attak110= 9;
+ public final static int FRAME_attak111= 10;
+ public final static int FRAME_attak112= 11;
+ public final static int FRAME_attak113= 12;
+ public final static int FRAME_attak114= 13;
+ public final static int FRAME_attak115= 14;
+ public final static int FRAME_attak116= 15;
+ public final static int FRAME_attak117= 16;
+ public final static int FRAME_attak118= 17;
+ public final static int FRAME_attak201= 18;
+ public final static int FRAME_attak202= 19;
+ public final static int FRAME_attak203= 20;
+ public final static int FRAME_attak204= 21;
+ public final static int FRAME_attak205= 22;
+ public final static int FRAME_attak206= 23;
+ public final static int FRAME_attak207= 24;
+ public final static int FRAME_attak208= 25;
+ public final static int FRAME_attak209= 26;
+ public final static int FRAME_attak210= 27;
+ public final static int FRAME_attak211= 28;
+ public final static int FRAME_attak212= 29;
+ public final static int FRAME_attak213= 30;
+ public final static int FRAME_death01= 31;
+ public final static int FRAME_death02= 32;
+ public final static int FRAME_death03= 33;
+ public final static int FRAME_death04= 34;
+ public final static int FRAME_death05= 35;
+ public final static int FRAME_death06= 36;
+ public final static int FRAME_death07= 37;
+ public final static int FRAME_death08= 38;
+ public final static int FRAME_death09= 39;
+ public final static int FRAME_death10= 40;
+ public final static int FRAME_death11= 41;
+ public final static int FRAME_death12= 42;
+ public final static int FRAME_death13= 43;
+ public final static int FRAME_death14= 44;
+ public final static int FRAME_death15= 45;
+ public final static int FRAME_death16= 46;
+ public final static int FRAME_death17= 47;
+ public final static int FRAME_death18= 48;
+ public final static int FRAME_death19= 49;
+ public final static int FRAME_death20= 50;
+ public final static int FRAME_death21= 51;
+ public final static int FRAME_death22= 52;
+ public final static int FRAME_death23= 53;
+ public final static int FRAME_death24= 54;
+ public final static int FRAME_death25= 55;
+ public final static int FRAME_death26= 56;
+ public final static int FRAME_death27= 57;
+ public final static int FRAME_death28= 58;
+ public final static int FRAME_death29= 59;
+ public final static int FRAME_death30= 60;
+ public final static int FRAME_death31= 61;
+ public final static int FRAME_death32= 62;
+ public final static int FRAME_death33= 63;
+ public final static int FRAME_death34= 64;
+ public final static int FRAME_death35= 65;
+ public final static int FRAME_death36= 66;
+ public final static int FRAME_death37= 67;
+ public final static int FRAME_death38= 68;
+ public final static int FRAME_death39= 69;
+ public final static int FRAME_death40= 70;
+ public final static int FRAME_death41= 71;
+ public final static int FRAME_death42= 72;
+ public final static int FRAME_death43= 73;
+ public final static int FRAME_death44= 74;
+ public final static int FRAME_death45= 75;
+ public final static int FRAME_death46= 76;
+ public final static int FRAME_death47= 77;
+ public final static int FRAME_death48= 78;
+ public final static int FRAME_death49= 79;
+ public final static int FRAME_death50= 80;
+ public final static int FRAME_pain101= 81;
+ public final static int FRAME_pain102= 82;
+ public final static int FRAME_pain103= 83;
+ public final static int FRAME_pain201= 84;
+ public final static int FRAME_pain202= 85;
+ public final static int FRAME_pain203= 86;
+ public final static int FRAME_pain301= 87;
+ public final static int FRAME_pain302= 88;
+ public final static int FRAME_pain303= 89;
+ public final static int FRAME_pain304= 90;
+ public final static int FRAME_pain305= 91;
+ public final static int FRAME_pain306= 92;
+ public final static int FRAME_pain307= 93;
+ public final static int FRAME_pain308= 94;
+ public final static int FRAME_pain309= 95;
+ public final static int FRAME_pain310= 96;
+ public final static int FRAME_pain311= 97;
+ public final static int FRAME_pain312= 98;
+ public final static int FRAME_pain313= 99;
+ public final static int FRAME_pain314= 100;
+ public final static int FRAME_pain315= 101;
+ public final static int FRAME_pain316= 102;
+ public final static int FRAME_pain317= 103;
+ public final static int FRAME_pain318= 104;
+ public final static int FRAME_pain319= 105;
+ public final static int FRAME_pain320= 106;
+ public final static int FRAME_pain321= 107;
+ public final static int FRAME_pain322= 108;
+ public final static int FRAME_pain323= 109;
+ public final static int FRAME_pain324= 110;
+ public final static int FRAME_pain325= 111;
+ public final static int FRAME_stand01= 112;
+ public final static int FRAME_stand02= 113;
+ public final static int FRAME_stand03= 114;
+ public final static int FRAME_stand04= 115;
+ public final static int FRAME_stand05= 116;
+ public final static int FRAME_stand06= 117;
+ public final static int FRAME_stand07= 118;
+ public final static int FRAME_stand08= 119;
+ public final static int FRAME_stand09= 120;
+ public final static int FRAME_stand10= 121;
+ public final static int FRAME_stand11= 122;
+ public final static int FRAME_stand12= 123;
+ public final static int FRAME_stand13= 124;
+ public final static int FRAME_stand14= 125;
+ public final static int FRAME_stand15= 126;
+ public final static int FRAME_stand16= 127;
+ public final static int FRAME_stand17= 128;
+ public final static int FRAME_stand18= 129;
+ public final static int FRAME_stand19= 130;
+ public final static int FRAME_stand20= 131;
+ public final static int FRAME_stand21= 132;
+ public final static int FRAME_stand22= 133;
+ public final static int FRAME_stand23= 134;
+ public final static int FRAME_stand24= 135;
+ public final static int FRAME_stand25= 136;
+ public final static int FRAME_stand26= 137;
+ public final static int FRAME_stand27= 138;
+ public final static int FRAME_stand28= 139;
+ public final static int FRAME_stand29= 140;
+ public final static int FRAME_stand30= 141;
+ public final static int FRAME_stand31= 142;
+ public final static int FRAME_stand32= 143;
+ public final static int FRAME_stand33= 144;
+ public final static int FRAME_stand34= 145;
+ public final static int FRAME_stand35= 146;
+ public final static int FRAME_stand36= 147;
+ public final static int FRAME_stand37= 148;
+ public final static int FRAME_stand38= 149;
+ public final static int FRAME_stand39= 150;
+ public final static int FRAME_stand40= 151;
+ public final static int FRAME_stand41= 152;
+ public final static int FRAME_stand42= 153;
+ public final static int FRAME_stand43= 154;
+ public final static int FRAME_stand44= 155;
+ public final static int FRAME_stand45= 156;
+ public final static int FRAME_stand46= 157;
+ public final static int FRAME_stand47= 158;
+ public final static int FRAME_stand48= 159;
+ public final static int FRAME_stand49= 160;
+ public final static int FRAME_stand50= 161;
+ public final static int FRAME_stand51= 162;
+ public final static int FRAME_walk01= 163;
+ public final static int FRAME_walk02= 164;
+ public final static int FRAME_walk03= 165;
+ public final static int FRAME_walk04= 166;
+ public final static int FRAME_walk05= 167;
+ public final static int FRAME_walk06= 168;
+ public final static int FRAME_walk07= 169;
+ public final static int FRAME_walk08= 170;
+ public final static int FRAME_walk09= 171;
+ public final static int FRAME_walk10= 172;
+ public final static int FRAME_walk11= 173;
+ public final static int FRAME_walk12= 174;
+ public final static int FRAME_walk13= 175;
+ public final static int FRAME_walk14= 176;
+ public final static int FRAME_walk15= 177;
+ public final static int FRAME_walk16= 178;
+ public final static int FRAME_walk17= 179;
+ public final static int FRAME_walk18= 180;
+ public final static int FRAME_walk19= 181;
+ public final static int FRAME_walk20= 182;
+ public final static int FRAME_walk21= 183;
+ public final static int FRAME_walk22= 184;
+ public final static int FRAME_walk23= 185;
+ public final static int FRAME_walk24= 186;
+ public final static int FRAME_walk25= 187;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ /*
+ ==============================================================================
+
+ jorg
+
+ ==============================================================================
+ */
+
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_pain3;
+ static int sound_idle;
+ static int sound_death;
+ static int sound_search1;
+ static int sound_search2;
+ static int sound_search3;
+ static int sound_attack1;
+ static int sound_attack2;
+ static int sound_firegun;
+ static int sound_step_left;
+ static int sound_step_right;
+ static int sound_death_hit;
+
+ /*
+ static EntThinkAdapter xxx = new EntThinkAdapter()
+ {
+ public boolean think(edict_t self)
+ {
+ return true;
+ }
+ };
+ */
+
+ static EntThinkAdapter jorg_search= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float r;
+
+ r= Lib.random();
+
+ if (r <= 0.3)
+ gi.sound(self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
+ else if (r <= 0.6)
+ gi.sound(self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_search3, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_idle= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_death_hit= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_death_hit, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_step_left= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_step_left, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_step_right= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_step_right, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= jorg_move_stand;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_reattack1= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (visible(self, self.enemy))
+ if (Lib.random() < 0.9)
+ self.monsterinfo.currentmove= jorg_move_attack1;
+ else {
+ self.s.sound= 0;
+ self.monsterinfo.currentmove= jorg_move_end_attack1;
+ }
+ else {
+ self.s.sound= 0;
+ self.monsterinfo.currentmove= jorg_move_end_attack1;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_attack1= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= jorg_move_attack1;
+ return true;
+ }
+ };
+
+ static EntPainAdapter jorg_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ self.s.sound= 0;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ // Lessen the chance of him going into his pain frames if he takes little damage
+ if (damage <= 40)
+ if (Lib.random() <= 0.6)
+ return;
+
+ /*
+ If he's entering his attack1 or using attack1, lessen the chance of him
+ going into pain
+ */
+
+ if ((self.s.frame >= FRAME_attak101) && (self.s.frame <= FRAME_attak108))
+ if (Lib.random() <= 0.005)
+ return;
+
+ if ((self.s.frame >= FRAME_attak109) && (self.s.frame <= FRAME_attak114))
+ if (Lib.random() <= 0.00005)
+ return;
+
+ if ((self.s.frame >= FRAME_attak201) && (self.s.frame <= FRAME_attak208))
+ if (Lib.random() <= 0.005)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (damage <= 50) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= jorg_move_pain1;
+ } else if (damage <= 100) {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= jorg_move_pain2;
+ } else {
+ if (Lib.random() <= 0.3) {
+ gi.sound(self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= jorg_move_pain3;
+ }
+ }
+
+ }
+ };
+
+ static EntThinkAdapter jorgBFG= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+
+ float[] start= { 0, 0, 0 };
+ float[] dir= { 0, 0, 0 };
+ float[] vec= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_JORG_BFG_1],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+ gi.sound(self, CHAN_VOICE, sound_attack2, 1, ATTN_NORM, 0);
+ /*void monster_fire_bfg (edict_t self,
+ float [] start,
+ float [] aimdir,
+ int damage,
+ int speed,
+ int kick,
+ float damage_radius,
+ int flashtype)*/
+ Monster.monster_fire_bfg(self, start, dir, 50, 300, 100, 200, MZ2_JORG_BFG_1);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_firebullet_right= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, target= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_JORG_MACHINEGUN_R1],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorMA(self.enemy.s.origin, -0.2f, self.enemy.velocity, target);
+ target[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(target, start, forward);
+ Math3D.VectorNormalize(forward);
+
+ Monster.monster_fire_bullet(
+ self,
+ start,
+ forward,
+ 6,
+ 4,
+ DEFAULT_BULLET_HSPREAD,
+ DEFAULT_BULLET_VSPREAD,
+ MZ2_JORG_MACHINEGUN_R1);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter xxx= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_firebullet_left= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 }, target= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_JORG_MACHINEGUN_L1],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorMA(self.enemy.s.origin, -0.2f, self.enemy.velocity, target);
+ target[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(target, start, forward);
+ Math3D.VectorNormalize(forward);
+
+ Monster.monster_fire_bullet(
+ self,
+ start,
+ forward,
+ 6,
+ 4,
+ DEFAULT_BULLET_HSPREAD,
+ DEFAULT_BULLET_VSPREAD,
+ MZ2_JORG_MACHINEGUN_L1);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_firebullet= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ jorg_firebullet_left.think(self);
+ jorg_firebullet_right.think(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] vec= { 0, 0, 0 };
+ float range= 0;
+
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, vec);
+ range= Math3D.VectorLength(vec);
+
+ if (Lib.random() <= 0.75) {
+ gi.sound(self, CHAN_VOICE, sound_attack1, 1, ATTN_NORM, 0);
+ self.s.sound= gi.soundindex("boss3/w_loop.wav");
+ self.monsterinfo.currentmove= jorg_move_start_attack1;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_attack2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= jorg_move_attack2;
+ }
+ return true;
+ }
+ };
+
+ /** Was disabled. RST. */
+ static EntThinkAdapter jorg_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ /*
+ edict_t tempent;
+
+ //VectorSet (self.mins, -16, -16, -24);
+ //VectorSet (self.maxs, 16, 16, -8);
+ // Jorg is on modelindex2. Do not clear him.
+ VectorSet(
+ self.mins,
+ -60,
+ -60,
+ 0);
+ VectorSet(self.maxs, 60, 60, 72);
+ self.movetype= MOVETYPE_TOSS;
+ self.nextthink= 0;
+ gi.linkentity(self);
+
+ tempent= G_Spawn();
+ VectorCopy(self.s.origin, tempent.s.origin);
+ VectorCopy(self.s.angles, tempent.s.angles);
+ tempent.killtarget= self.killtarget;
+ tempent.target= self.target;
+ tempent.activator= self.enemy;
+ self.killtarget= 0;
+ self.target= 0;
+ SP_monster_makron(tempent);
+
+ */
+ return true;
+ }
+ };
+
+ static EntDieAdapter jorg_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_NO;
+ self.s.sound= 0;
+ self.count= 0;
+ self.monsterinfo.currentmove= jorg_move_death;
+ return;
+ }
+ };
+
+ static EntThinkAdapter Jorg_CheckAttack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] spot1= { 0, 0, 0 }, spot2= { 0, 0, 0 };
+ float[] temp= { 0, 0, 0 };
+ float chance;
+ trace_t tr;
+ boolean enemy_infront;
+ int enemy_range;
+ float enemy_yaw;
+
+ if (self.enemy.health > 0) {
+ // see if any entities are in the way of the shot
+ Math3D.VectorCopy(self.s.origin, spot1);
+ spot1[2] += self.viewheight;
+ Math3D.VectorCopy(self.enemy.s.origin, spot2);
+ spot2[2] += self.enemy.viewheight;
+
+ tr=
+ gi.trace(
+ spot1,
+ null,
+ null,
+ spot2,
+ self,
+ CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA);
+
+ // do we have a clear shot?
+ if (tr.ent != self.enemy)
+ return false;
+ }
+
+ enemy_infront= infront(self, self.enemy);
+ enemy_range= range(self, self.enemy);
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp);
+ enemy_yaw= Math3D.vectoyaw(temp);
+
+ self.ideal_yaw= enemy_yaw;
+
+ // melee attack
+ if (enemy_range == RANGE_MELEE) {
+ if (self.monsterinfo.melee != null)
+ self.monsterinfo.attack_state= AS_MELEE;
+ else
+ self.monsterinfo.attack_state= AS_MISSILE;
+ return true;
+ }
+
+ // missile attack ?
+ if (self.monsterinfo.attack == null)
+ return false;
+
+ if (level.time < self.monsterinfo.attack_finished)
+ return false;
+
+ if (enemy_range == RANGE_FAR)
+ return false;
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ chance= 0.4f;
+ } else if (enemy_range == RANGE_MELEE) {
+ chance= 0.8f;
+ } else if (enemy_range == RANGE_NEAR) {
+ chance= 0.4f;
+ } else if (enemy_range == RANGE_MID) {
+ chance= 0.2f;
+ } else {
+ return false;
+ }
+
+ if (Lib.random() < chance) {
+ self.monsterinfo.attack_state= AS_MISSILE;
+ self.monsterinfo.attack_finished= level.time + 2 * Lib.random();
+ return true;
+ }
+
+ if ((self.flags & FL_FLY) != 0) {
+ if (Lib.random() < 0.3)
+ self.monsterinfo.attack_state= AS_SLIDING;
+ else
+ self.monsterinfo.attack_state= AS_STRAIGHT;
+ }
+
+ return false;
+ }
+ };
+
+ //
+ // stand
+ //
+
+ static mframe_t jorg_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, jorg_idle),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 10
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 20
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 30
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 19, null),
+ new mframe_t(ai_stand, 11, jorg_step_left),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 6, null),
+ new mframe_t(ai_stand, 9, jorg_step_right),
+ new mframe_t(ai_stand, 0, null),
+ // 40
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -2, null),
+ new mframe_t(ai_stand, -17, jorg_step_left),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -12, null),
+ // 50
+ new mframe_t(ai_stand, -14, jorg_step_right) // 51
+ };
+ static mmove_t jorg_move_stand=
+ new mmove_t(FRAME_stand01, FRAME_stand51, jorg_frames_stand, null);
+
+ static mframe_t jorg_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 17, jorg_step_left),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 33, jorg_step_right),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 9, null)};
+ static mmove_t jorg_move_run= new mmove_t(FRAME_walk06, FRAME_walk19, jorg_frames_run, null);
+
+ //
+ // walk
+ //
+
+ static mframe_t jorg_frames_start_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 15, null)};
+ static mmove_t jorg_move_start_walk=
+ new mmove_t(FRAME_walk01, FRAME_walk05, jorg_frames_start_walk, null);
+
+ static mframe_t jorg_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 17, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 12, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 10, null),
+ new mframe_t(ai_walk, 33, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 9, null)};
+ static mmove_t jorg_move_walk= new mmove_t(FRAME_walk06, FRAME_walk19, jorg_frames_walk, null);
+
+ static mframe_t jorg_frames_end_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 11, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, -8, null)};
+ static mmove_t jorg_move_end_walk=
+ new mmove_t(FRAME_walk20, FRAME_walk25, jorg_frames_end_walk, null);
+
+ static EntThinkAdapter jorg_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= jorg_move_walk;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter jorg_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove= jorg_move_stand;
+ else
+ self.monsterinfo.currentmove= jorg_move_run;
+ return true;
+ }
+ };
+
+ static mframe_t jorg_frames_pain3[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -28, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -3, jorg_step_left),
+ new mframe_t(ai_move, -9, null),
+ new mframe_t(ai_move, 0, jorg_step_right),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, -11, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 10, null),
+ new mframe_t(ai_move, 11, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 10, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 10, null),
+ new mframe_t(ai_move, 7, jorg_step_left),
+ new mframe_t(ai_move, 17, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, jorg_step_right)};
+
+ static mmove_t jorg_move_pain3=
+ new mmove_t(FRAME_pain301, FRAME_pain325, jorg_frames_pain3, jorg_run);
+
+ static mframe_t jorg_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t jorg_move_pain2=
+ new mmove_t(FRAME_pain201, FRAME_pain203, jorg_frames_pain2, jorg_run);
+
+ static mframe_t jorg_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t jorg_move_pain1=
+ new mmove_t(FRAME_pain101, FRAME_pain103, jorg_frames_pain1, jorg_run);
+
+ static mframe_t jorg_frames_death1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 10
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 20
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 30
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 40
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, M_Boss32.MakronToss),
+ new mframe_t(ai_move, 0, BossExplode) // 50
+ };
+
+ static mmove_t jorg_move_death=
+ new mmove_t(FRAME_death01, FRAME_death50, jorg_frames_death1, jorg_dead);
+
+ static mframe_t jorg_frames_attack2[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, jorgBFG),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t jorg_move_attack2=
+ new mmove_t(FRAME_attak201, FRAME_attak213, jorg_frames_attack2, jorg_run);
+
+ static mframe_t jorg_frames_start_attack1[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+
+ static mmove_t jorg_move_start_attack1=
+ new mmove_t(FRAME_attak101, FRAME_attak108, jorg_frames_start_attack1, jorg_attack1);
+
+ static mframe_t jorg_frames_attack1[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, jorg_firebullet),
+ new mframe_t(ai_charge, 0, jorg_firebullet),
+ new mframe_t(ai_charge, 0, jorg_firebullet),
+ new mframe_t(ai_charge, 0, jorg_firebullet),
+ new mframe_t(ai_charge, 0, jorg_firebullet),
+ new mframe_t(ai_charge, 0, jorg_firebullet)};
+
+ static mmove_t jorg_move_attack1=
+ new mmove_t(FRAME_attak109, FRAME_attak114, jorg_frames_attack1, jorg_reattack1);
+
+ static mframe_t jorg_frames_end_attack1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t jorg_move_end_attack1=
+ new mmove_t(FRAME_attak115, FRAME_attak118, jorg_frames_end_attack1, jorg_run);
+
+ /*QUAKED monster_jorg (1 .5 0) (-80 -80 0) (90 90 140) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_jorg(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_pain1= gi.soundindex("boss3/bs3pain1.wav");
+ sound_pain2= gi.soundindex("boss3/bs3pain2.wav");
+ sound_pain3= gi.soundindex("boss3/bs3pain3.wav");
+ sound_death= gi.soundindex("boss3/bs3deth1.wav");
+ sound_attack1= gi.soundindex("boss3/bs3atck1.wav");
+ sound_attack2= gi.soundindex("boss3/bs3atck2.wav");
+ sound_search1= gi.soundindex("boss3/bs3srch1.wav");
+ sound_search2= gi.soundindex("boss3/bs3srch2.wav");
+ sound_search3= gi.soundindex("boss3/bs3srch3.wav");
+ sound_idle= gi.soundindex("boss3/bs3idle1.wav");
+ sound_step_left= gi.soundindex("boss3/step1.wav");
+ sound_step_right= gi.soundindex("boss3/step2.wav");
+ sound_firegun= gi.soundindex("boss3/xfire.wav");
+ sound_death_hit= gi.soundindex("boss3/d_hit.wav");
+
+ M_Boss32.MakronPrecache();
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/boss3/rider/tris.md2");
+ self.s.modelindex2= gi.modelindex("models/monsters/boss3/jorg/tris.md2");
+ Math3D.VectorSet(self.mins, -80, -80, 0);
+ Math3D.VectorSet(self.maxs, 80, 80, 140);
+
+ self.health= 3000;
+ self.gib_health= -2000;
+ self.mass= 1000;
+
+ self.pain= jorg_pain;
+ self.die= jorg_die;
+ self.monsterinfo.stand= jorg_stand;
+ self.monsterinfo.walk= jorg_walk;
+ self.monsterinfo.run= jorg_run;
+ self.monsterinfo.dodge= null;
+ self.monsterinfo.attack= jorg_attack;
+ self.monsterinfo.search= jorg_search;
+ self.monsterinfo.melee= null;
+ self.monsterinfo.sight= null;
+ self.monsterinfo.checkattack= Jorg_CheckAttack;
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove= jorg_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Boss32.java b/src/jake2/game/M_Boss32.java
new file mode 100644
index 0000000..fef2a14
--- /dev/null
+++ b/src/jake2/game/M_Boss32.java
@@ -0,0 +1,1469 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Boss32.java,v 1.1 2004-07-07 19:59:10 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Boss32 extends GameWeapon {
+
+ public final static int FRAME_attak101= 0;
+ public final static int FRAME_attak102= 1;
+ public final static int FRAME_attak103= 2;
+ public final static int FRAME_attak104= 3;
+ public final static int FRAME_attak105= 4;
+ public final static int FRAME_attak106= 5;
+ public final static int FRAME_attak107= 6;
+ public final static int FRAME_attak108= 7;
+ public final static int FRAME_attak109= 8;
+ public final static int FRAME_attak110= 9;
+ public final static int FRAME_attak111= 10;
+ public final static int FRAME_attak112= 11;
+ public final static int FRAME_attak113= 12;
+ public final static int FRAME_attak114= 13;
+ public final static int FRAME_attak115= 14;
+ public final static int FRAME_attak116= 15;
+ public final static int FRAME_attak117= 16;
+ public final static int FRAME_attak118= 17;
+ public final static int FRAME_attak201= 18;
+ public final static int FRAME_attak202= 19;
+ public final static int FRAME_attak203= 20;
+ public final static int FRAME_attak204= 21;
+ public final static int FRAME_attak205= 22;
+ public final static int FRAME_attak206= 23;
+ public final static int FRAME_attak207= 24;
+ public final static int FRAME_attak208= 25;
+ public final static int FRAME_attak209= 26;
+ public final static int FRAME_attak210= 27;
+ public final static int FRAME_attak211= 28;
+ public final static int FRAME_attak212= 29;
+ public final static int FRAME_attak213= 30;
+ public final static int FRAME_death01= 31;
+ public final static int FRAME_death02= 32;
+ public final static int FRAME_death03= 33;
+ public final static int FRAME_death04= 34;
+ public final static int FRAME_death05= 35;
+ public final static int FRAME_death06= 36;
+ public final static int FRAME_death07= 37;
+ public final static int FRAME_death08= 38;
+ public final static int FRAME_death09= 39;
+ public final static int FRAME_death10= 40;
+ public final static int FRAME_death11= 41;
+ public final static int FRAME_death12= 42;
+ public final static int FRAME_death13= 43;
+ public final static int FRAME_death14= 44;
+ public final static int FRAME_death15= 45;
+ public final static int FRAME_death16= 46;
+ public final static int FRAME_death17= 47;
+ public final static int FRAME_death18= 48;
+ public final static int FRAME_death19= 49;
+ public final static int FRAME_death20= 50;
+ public final static int FRAME_death21= 51;
+ public final static int FRAME_death22= 52;
+ public final static int FRAME_death23= 53;
+ public final static int FRAME_death24= 54;
+ public final static int FRAME_death25= 55;
+ public final static int FRAME_death26= 56;
+ public final static int FRAME_death27= 57;
+ public final static int FRAME_death28= 58;
+ public final static int FRAME_death29= 59;
+ public final static int FRAME_death30= 60;
+ public final static int FRAME_death31= 61;
+ public final static int FRAME_death32= 62;
+ public final static int FRAME_death33= 63;
+ public final static int FRAME_death34= 64;
+ public final static int FRAME_death35= 65;
+ public final static int FRAME_death36= 66;
+ public final static int FRAME_death37= 67;
+ public final static int FRAME_death38= 68;
+ public final static int FRAME_death39= 69;
+ public final static int FRAME_death40= 70;
+ public final static int FRAME_death41= 71;
+ public final static int FRAME_death42= 72;
+ public final static int FRAME_death43= 73;
+ public final static int FRAME_death44= 74;
+ public final static int FRAME_death45= 75;
+ public final static int FRAME_death46= 76;
+ public final static int FRAME_death47= 77;
+ public final static int FRAME_death48= 78;
+ public final static int FRAME_death49= 79;
+ public final static int FRAME_death50= 80;
+ public final static int FRAME_pain101= 81;
+ public final static int FRAME_pain102= 82;
+ public final static int FRAME_pain103= 83;
+ public final static int FRAME_pain201= 84;
+ public final static int FRAME_pain202= 85;
+ public final static int FRAME_pain203= 86;
+ public final static int FRAME_pain301= 87;
+ public final static int FRAME_pain302= 88;
+ public final static int FRAME_pain303= 89;
+ public final static int FRAME_pain304= 90;
+ public final static int FRAME_pain305= 91;
+ public final static int FRAME_pain306= 92;
+ public final static int FRAME_pain307= 93;
+ public final static int FRAME_pain308= 94;
+ public final static int FRAME_pain309= 95;
+ public final static int FRAME_pain310= 96;
+ public final static int FRAME_pain311= 97;
+ public final static int FRAME_pain312= 98;
+ public final static int FRAME_pain313= 99;
+ public final static int FRAME_pain314= 100;
+ public final static int FRAME_pain315= 101;
+ public final static int FRAME_pain316= 102;
+ public final static int FRAME_pain317= 103;
+ public final static int FRAME_pain318= 104;
+ public final static int FRAME_pain319= 105;
+ public final static int FRAME_pain320= 106;
+ public final static int FRAME_pain321= 107;
+ public final static int FRAME_pain322= 108;
+ public final static int FRAME_pain323= 109;
+ public final static int FRAME_pain324= 110;
+ public final static int FRAME_pain325= 111;
+ public final static int FRAME_stand01= 112;
+ public final static int FRAME_stand02= 113;
+ public final static int FRAME_stand03= 114;
+ public final static int FRAME_stand04= 115;
+ public final static int FRAME_stand05= 116;
+ public final static int FRAME_stand06= 117;
+ public final static int FRAME_stand07= 118;
+ public final static int FRAME_stand08= 119;
+ public final static int FRAME_stand09= 120;
+ public final static int FRAME_stand10= 121;
+ public final static int FRAME_stand11= 122;
+ public final static int FRAME_stand12= 123;
+ public final static int FRAME_stand13= 124;
+ public final static int FRAME_stand14= 125;
+ public final static int FRAME_stand15= 126;
+ public final static int FRAME_stand16= 127;
+ public final static int FRAME_stand17= 128;
+ public final static int FRAME_stand18= 129;
+ public final static int FRAME_stand19= 130;
+ public final static int FRAME_stand20= 131;
+ public final static int FRAME_stand21= 132;
+ public final static int FRAME_stand22= 133;
+ public final static int FRAME_stand23= 134;
+ public final static int FRAME_stand24= 135;
+ public final static int FRAME_stand25= 136;
+ public final static int FRAME_stand26= 137;
+ public final static int FRAME_stand27= 138;
+ public final static int FRAME_stand28= 139;
+ public final static int FRAME_stand29= 140;
+ public final static int FRAME_stand30= 141;
+ public final static int FRAME_stand31= 142;
+ public final static int FRAME_stand32= 143;
+ public final static int FRAME_stand33= 144;
+ public final static int FRAME_stand34= 145;
+ public final static int FRAME_stand35= 146;
+ public final static int FRAME_stand36= 147;
+ public final static int FRAME_stand37= 148;
+ public final static int FRAME_stand38= 149;
+ public final static int FRAME_stand39= 150;
+ public final static int FRAME_stand40= 151;
+ public final static int FRAME_stand41= 152;
+ public final static int FRAME_stand42= 153;
+ public final static int FRAME_stand43= 154;
+ public final static int FRAME_stand44= 155;
+ public final static int FRAME_stand45= 156;
+ public final static int FRAME_stand46= 157;
+ public final static int FRAME_stand47= 158;
+ public final static int FRAME_stand48= 159;
+ public final static int FRAME_stand49= 160;
+ public final static int FRAME_stand50= 161;
+ public final static int FRAME_stand51= 162;
+ public final static int FRAME_walk01= 163;
+ public final static int FRAME_walk02= 164;
+ public final static int FRAME_walk03= 165;
+ public final static int FRAME_walk04= 166;
+ public final static int FRAME_walk05= 167;
+ public final static int FRAME_walk06= 168;
+ public final static int FRAME_walk07= 169;
+ public final static int FRAME_walk08= 170;
+ public final static int FRAME_walk09= 171;
+ public final static int FRAME_walk10= 172;
+ public final static int FRAME_walk11= 173;
+ public final static int FRAME_walk12= 174;
+ public final static int FRAME_walk13= 175;
+ public final static int FRAME_walk14= 176;
+ public final static int FRAME_walk15= 177;
+ public final static int FRAME_walk16= 178;
+ public final static int FRAME_walk17= 179;
+ public final static int FRAME_walk18= 180;
+ public final static int FRAME_walk19= 181;
+ public final static int FRAME_walk20= 182;
+ public final static int FRAME_walk21= 183;
+ public final static int FRAME_walk22= 184;
+ public final static int FRAME_walk23= 185;
+ public final static int FRAME_walk24= 186;
+ public final static int FRAME_walk25= 187;
+ public final static int FRAME_active01= 188;
+ public final static int FRAME_active02= 189;
+ public final static int FRAME_active03= 190;
+ public final static int FRAME_active04= 191;
+ public final static int FRAME_active05= 192;
+ public final static int FRAME_active06= 193;
+ public final static int FRAME_active07= 194;
+ public final static int FRAME_active08= 195;
+ public final static int FRAME_active09= 196;
+ public final static int FRAME_active10= 197;
+ public final static int FRAME_active11= 198;
+ public final static int FRAME_active12= 199;
+ public final static int FRAME_active13= 200;
+ public final static int FRAME_attak301= 201;
+ public final static int FRAME_attak302= 202;
+ public final static int FRAME_attak303= 203;
+ public final static int FRAME_attak304= 204;
+ public final static int FRAME_attak305= 205;
+ public final static int FRAME_attak306= 206;
+ public final static int FRAME_attak307= 207;
+ public final static int FRAME_attak308= 208;
+ public final static int FRAME_attak401= 209;
+ public final static int FRAME_attak402= 210;
+ public final static int FRAME_attak403= 211;
+ public final static int FRAME_attak404= 212;
+ public final static int FRAME_attak405= 213;
+ public final static int FRAME_attak406= 214;
+ public final static int FRAME_attak407= 215;
+ public final static int FRAME_attak408= 216;
+ public final static int FRAME_attak409= 217;
+ public final static int FRAME_attak410= 218;
+ public final static int FRAME_attak411= 219;
+ public final static int FRAME_attak412= 220;
+ public final static int FRAME_attak413= 221;
+ public final static int FRAME_attak414= 222;
+ public final static int FRAME_attak415= 223;
+ public final static int FRAME_attak416= 224;
+ public final static int FRAME_attak417= 225;
+ public final static int FRAME_attak418= 226;
+ public final static int FRAME_attak419= 227;
+ public final static int FRAME_attak420= 228;
+ public final static int FRAME_attak421= 229;
+ public final static int FRAME_attak422= 230;
+ public final static int FRAME_attak423= 231;
+ public final static int FRAME_attak424= 232;
+ public final static int FRAME_attak425= 233;
+ public final static int FRAME_attak426= 234;
+ public final static int FRAME_attak501= 235;
+ public final static int FRAME_attak502= 236;
+ public final static int FRAME_attak503= 237;
+ public final static int FRAME_attak504= 238;
+ public final static int FRAME_attak505= 239;
+ public final static int FRAME_attak506= 240;
+ public final static int FRAME_attak507= 241;
+ public final static int FRAME_attak508= 242;
+ public final static int FRAME_attak509= 243;
+ public final static int FRAME_attak510= 244;
+ public final static int FRAME_attak511= 245;
+ public final static int FRAME_attak512= 246;
+ public final static int FRAME_attak513= 247;
+ public final static int FRAME_attak514= 248;
+ public final static int FRAME_attak515= 249;
+ public final static int FRAME_attak516= 250;
+ public final static int FRAME_death201= 251;
+ public final static int FRAME_death202= 252;
+ public final static int FRAME_death203= 253;
+ public final static int FRAME_death204= 254;
+ public final static int FRAME_death205= 255;
+ public final static int FRAME_death206= 256;
+ public final static int FRAME_death207= 257;
+ public final static int FRAME_death208= 258;
+ public final static int FRAME_death209= 259;
+ public final static int FRAME_death210= 260;
+ public final static int FRAME_death211= 261;
+ public final static int FRAME_death212= 262;
+ public final static int FRAME_death213= 263;
+ public final static int FRAME_death214= 264;
+ public final static int FRAME_death215= 265;
+ public final static int FRAME_death216= 266;
+ public final static int FRAME_death217= 267;
+ public final static int FRAME_death218= 268;
+ public final static int FRAME_death219= 269;
+ public final static int FRAME_death220= 270;
+ public final static int FRAME_death221= 271;
+ public final static int FRAME_death222= 272;
+ public final static int FRAME_death223= 273;
+ public final static int FRAME_death224= 274;
+ public final static int FRAME_death225= 275;
+ public final static int FRAME_death226= 276;
+ public final static int FRAME_death227= 277;
+ public final static int FRAME_death228= 278;
+ public final static int FRAME_death229= 279;
+ public final static int FRAME_death230= 280;
+ public final static int FRAME_death231= 281;
+ public final static int FRAME_death232= 282;
+ public final static int FRAME_death233= 283;
+ public final static int FRAME_death234= 284;
+ public final static int FRAME_death235= 285;
+ public final static int FRAME_death236= 286;
+ public final static int FRAME_death237= 287;
+ public final static int FRAME_death238= 288;
+ public final static int FRAME_death239= 289;
+ public final static int FRAME_death240= 290;
+ public final static int FRAME_death241= 291;
+ public final static int FRAME_death242= 292;
+ public final static int FRAME_death243= 293;
+ public final static int FRAME_death244= 294;
+ public final static int FRAME_death245= 295;
+ public final static int FRAME_death246= 296;
+ public final static int FRAME_death247= 297;
+ public final static int FRAME_death248= 298;
+ public final static int FRAME_death249= 299;
+ public final static int FRAME_death250= 300;
+ public final static int FRAME_death251= 301;
+ public final static int FRAME_death252= 302;
+ public final static int FRAME_death253= 303;
+ public final static int FRAME_death254= 304;
+ public final static int FRAME_death255= 305;
+ public final static int FRAME_death256= 306;
+ public final static int FRAME_death257= 307;
+ public final static int FRAME_death258= 308;
+ public final static int FRAME_death259= 309;
+ public final static int FRAME_death260= 310;
+ public final static int FRAME_death261= 311;
+ public final static int FRAME_death262= 312;
+ public final static int FRAME_death263= 313;
+ public final static int FRAME_death264= 314;
+ public final static int FRAME_death265= 315;
+ public final static int FRAME_death266= 316;
+ public final static int FRAME_death267= 317;
+ public final static int FRAME_death268= 318;
+ public final static int FRAME_death269= 319;
+ public final static int FRAME_death270= 320;
+ public final static int FRAME_death271= 321;
+ public final static int FRAME_death272= 322;
+ public final static int FRAME_death273= 323;
+ public final static int FRAME_death274= 324;
+ public final static int FRAME_death275= 325;
+ public final static int FRAME_death276= 326;
+ public final static int FRAME_death277= 327;
+ public final static int FRAME_death278= 328;
+ public final static int FRAME_death279= 329;
+ public final static int FRAME_death280= 330;
+ public final static int FRAME_death281= 331;
+ public final static int FRAME_death282= 332;
+ public final static int FRAME_death283= 333;
+ public final static int FRAME_death284= 334;
+ public final static int FRAME_death285= 335;
+ public final static int FRAME_death286= 336;
+ public final static int FRAME_death287= 337;
+ public final static int FRAME_death288= 338;
+ public final static int FRAME_death289= 339;
+ public final static int FRAME_death290= 340;
+ public final static int FRAME_death291= 341;
+ public final static int FRAME_death292= 342;
+ public final static int FRAME_death293= 343;
+ public final static int FRAME_death294= 344;
+ public final static int FRAME_death295= 345;
+ public final static int FRAME_death301= 346;
+ public final static int FRAME_death302= 347;
+ public final static int FRAME_death303= 348;
+ public final static int FRAME_death304= 349;
+ public final static int FRAME_death305= 350;
+ public final static int FRAME_death306= 351;
+ public final static int FRAME_death307= 352;
+ public final static int FRAME_death308= 353;
+ public final static int FRAME_death309= 354;
+ public final static int FRAME_death310= 355;
+ public final static int FRAME_death311= 356;
+ public final static int FRAME_death312= 357;
+ public final static int FRAME_death313= 358;
+ public final static int FRAME_death314= 359;
+ public final static int FRAME_death315= 360;
+ public final static int FRAME_death316= 361;
+ public final static int FRAME_death317= 362;
+ public final static int FRAME_death318= 363;
+ public final static int FRAME_death319= 364;
+ public final static int FRAME_death320= 365;
+ public final static int FRAME_jump01= 366;
+ public final static int FRAME_jump02= 367;
+ public final static int FRAME_jump03= 368;
+ public final static int FRAME_jump04= 369;
+ public final static int FRAME_jump05= 370;
+ public final static int FRAME_jump06= 371;
+ public final static int FRAME_jump07= 372;
+ public final static int FRAME_jump08= 373;
+ public final static int FRAME_jump09= 374;
+ public final static int FRAME_jump10= 375;
+ public final static int FRAME_jump11= 376;
+ public final static int FRAME_jump12= 377;
+ public final static int FRAME_jump13= 378;
+ public final static int FRAME_pain401= 379;
+ public final static int FRAME_pain402= 380;
+ public final static int FRAME_pain403= 381;
+ public final static int FRAME_pain404= 382;
+ public final static int FRAME_pain501= 383;
+ public final static int FRAME_pain502= 384;
+ public final static int FRAME_pain503= 385;
+ public final static int FRAME_pain504= 386;
+ public final static int FRAME_pain601= 387;
+ public final static int FRAME_pain602= 388;
+ public final static int FRAME_pain603= 389;
+ public final static int FRAME_pain604= 390;
+ public final static int FRAME_pain605= 391;
+ public final static int FRAME_pain606= 392;
+ public final static int FRAME_pain607= 393;
+ public final static int FRAME_pain608= 394;
+ public final static int FRAME_pain609= 395;
+ public final static int FRAME_pain610= 396;
+ public final static int FRAME_pain611= 397;
+ public final static int FRAME_pain612= 398;
+ public final static int FRAME_pain613= 399;
+ public final static int FRAME_pain614= 400;
+ public final static int FRAME_pain615= 401;
+ public final static int FRAME_pain616= 402;
+ public final static int FRAME_pain617= 403;
+ public final static int FRAME_pain618= 404;
+ public final static int FRAME_pain619= 405;
+ public final static int FRAME_pain620= 406;
+ public final static int FRAME_pain621= 407;
+ public final static int FRAME_pain622= 408;
+ public final static int FRAME_pain623= 409;
+ public final static int FRAME_pain624= 410;
+ public final static int FRAME_pain625= 411;
+ public final static int FRAME_pain626= 412;
+ public final static int FRAME_pain627= 413;
+ public final static int FRAME_stand201= 414;
+ public final static int FRAME_stand202= 415;
+ public final static int FRAME_stand203= 416;
+ public final static int FRAME_stand204= 417;
+ public final static int FRAME_stand205= 418;
+ public final static int FRAME_stand206= 419;
+ public final static int FRAME_stand207= 420;
+ public final static int FRAME_stand208= 421;
+ public final static int FRAME_stand209= 422;
+ public final static int FRAME_stand210= 423;
+ public final static int FRAME_stand211= 424;
+ public final static int FRAME_stand212= 425;
+ public final static int FRAME_stand213= 426;
+ public final static int FRAME_stand214= 427;
+ public final static int FRAME_stand215= 428;
+ public final static int FRAME_stand216= 429;
+ public final static int FRAME_stand217= 430;
+ public final static int FRAME_stand218= 431;
+ public final static int FRAME_stand219= 432;
+ public final static int FRAME_stand220= 433;
+ public final static int FRAME_stand221= 434;
+ public final static int FRAME_stand222= 435;
+ public final static int FRAME_stand223= 436;
+ public final static int FRAME_stand224= 437;
+ public final static int FRAME_stand225= 438;
+ public final static int FRAME_stand226= 439;
+ public final static int FRAME_stand227= 440;
+ public final static int FRAME_stand228= 441;
+ public final static int FRAME_stand229= 442;
+ public final static int FRAME_stand230= 443;
+ public final static int FRAME_stand231= 444;
+ public final static int FRAME_stand232= 445;
+ public final static int FRAME_stand233= 446;
+ public final static int FRAME_stand234= 447;
+ public final static int FRAME_stand235= 448;
+ public final static int FRAME_stand236= 449;
+ public final static int FRAME_stand237= 450;
+ public final static int FRAME_stand238= 451;
+ public final static int FRAME_stand239= 452;
+ public final static int FRAME_stand240= 453;
+ public final static int FRAME_stand241= 454;
+ public final static int FRAME_stand242= 455;
+ public final static int FRAME_stand243= 456;
+ public final static int FRAME_stand244= 457;
+ public final static int FRAME_stand245= 458;
+ public final static int FRAME_stand246= 459;
+ public final static int FRAME_stand247= 460;
+ public final static int FRAME_stand248= 461;
+ public final static int FRAME_stand249= 462;
+ public final static int FRAME_stand250= 463;
+ public final static int FRAME_stand251= 464;
+ public final static int FRAME_stand252= 465;
+ public final static int FRAME_stand253= 466;
+ public final static int FRAME_stand254= 467;
+ public final static int FRAME_stand255= 468;
+ public final static int FRAME_stand256= 469;
+ public final static int FRAME_stand257= 470;
+ public final static int FRAME_stand258= 471;
+ public final static int FRAME_stand259= 472;
+ public final static int FRAME_stand260= 473;
+ public final static int FRAME_walk201= 474;
+ public final static int FRAME_walk202= 475;
+ public final static int FRAME_walk203= 476;
+ public final static int FRAME_walk204= 477;
+ public final static int FRAME_walk205= 478;
+ public final static int FRAME_walk206= 479;
+ public final static int FRAME_walk207= 480;
+ public final static int FRAME_walk208= 481;
+ public final static int FRAME_walk209= 482;
+ public final static int FRAME_walk210= 483;
+ public final static int FRAME_walk211= 484;
+ public final static int FRAME_walk212= 485;
+ public final static int FRAME_walk213= 486;
+ public final static int FRAME_walk214= 487;
+ public final static int FRAME_walk215= 488;
+ public final static int FRAME_walk216= 489;
+ public final static int FRAME_walk217= 490;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_pain4;
+ static int sound_pain5;
+ static int sound_pain6;
+ static int sound_death;
+ static int sound_step_left;
+ static int sound_step_right;
+ static int sound_attack_bfg;
+ static int sound_brainsplorch;
+ static int sound_prerailgun;
+ static int sound_popup;
+ static int sound_taunt1;
+ static int sound_taunt2;
+ static int sound_taunt3;
+ static int sound_hit;
+
+ static EntThinkAdapter makron_taunt= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float r;
+
+ r= Lib.random();
+ if (r <= 0.3)
+ gi.sound(self, CHAN_AUTO, sound_taunt1, 1, ATTN_NONE, 0);
+ else if (r <= 0.6)
+ gi.sound(self, CHAN_AUTO, sound_taunt2, 1, ATTN_NONE, 0);
+ else
+ gi.sound(self, CHAN_AUTO, sound_taunt3, 1, ATTN_NONE, 0);
+ return true;
+ }
+ };
+
+ //
+ // stand
+ //
+ static EntThinkAdapter makron_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= makron_move_stand;
+ return true;
+ }
+ };
+
+ /*
+ static EntThinkAdapter xxx = new EntThinkAdapter()
+ {
+ public boolean think(edict_t self)
+ {
+ return true;
+ }
+ };
+ */
+
+ static EntThinkAdapter makron_hit= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_AUTO, sound_hit, 1, ATTN_NONE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_popup= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_popup, 1, ATTN_NONE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_step_left= new EntThinkAdapter() {
+
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_step_left, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_step_right= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_step_right, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_brainsplorch= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_brainsplorch, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_prerailgun= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_prerailgun, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t makron_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 10
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 20
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 30
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 40
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 50
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null) // 60
+ };
+
+ static mmove_t makron_move_stand=
+ new mmove_t(FRAME_stand201, FRAME_stand260, makron_frames_stand, null);
+
+ static mframe_t makron_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 3, makron_step_left),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, makron_step_right),
+ new mframe_t(ai_run, 6, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 6, null),
+ new mframe_t(ai_run, 12, null)};
+
+ static mmove_t makron_move_run=
+ new mmove_t(FRAME_walk204, FRAME_walk213, makron_frames_run, null);
+
+ static mframe_t makron_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 3, makron_step_left),
+ new mframe_t(ai_walk, 12, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 8, makron_step_right),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 12, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 12, null)};
+
+ static mmove_t makron_move_walk=
+ new mmove_t(FRAME_walk204, FRAME_walk213, makron_frames_run, null);
+
+ //
+ // death
+ //
+ static EntThinkAdapter makron_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -60, -60, 0);
+ Math3D.VectorSet(self.maxs, 60, 60, 72);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= makron_move_walk;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove= makron_move_stand;
+ else
+ self.monsterinfo.currentmove= makron_move_run;
+ return true;
+ }
+ };
+
+ static mframe_t makron_frames_pain6[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 10
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, makron_popup),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 20
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, makron_taunt),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t makron_move_pain6=
+ new mmove_t(FRAME_pain601, FRAME_pain627, makron_frames_pain6, makron_run);
+
+ static mframe_t makron_frames_pain5[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t makron_move_pain5=
+ new mmove_t(FRAME_pain501, FRAME_pain504, makron_frames_pain5, makron_run);
+
+ static mframe_t makron_frames_pain4[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t makron_move_pain4=
+ new mmove_t(FRAME_pain401, FRAME_pain404, makron_frames_pain4, makron_run);
+
+ static mframe_t makron_frames_death2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -15, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, -12, null),
+ new mframe_t(ai_move, 0, makron_step_left),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 10
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 11, null),
+ new mframe_t(ai_move, 12, null),
+ new mframe_t(ai_move, 11, makron_step_right),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 20
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 30
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, 7, null),
+ new mframe_t(ai_move, 6, makron_step_left),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 2, null),
+ // 40
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 50
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -6, makron_step_right),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -4, makron_step_left),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 60
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -3, makron_step_right),
+ new mframe_t(ai_move, -8, null),
+ new mframe_t(ai_move, -3, makron_step_left),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -4, makron_step_right),
+ // 70
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, 0, makron_step_left),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 80
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ // 90
+ new mframe_t(ai_move, 27, makron_hit),
+ new mframe_t(ai_move, 26, null),
+ new mframe_t(ai_move, 0, makron_brainsplorch),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null) // 95
+ };
+
+ static mmove_t makron_move_death2=
+ new mmove_t(FRAME_death201, FRAME_death295, makron_frames_death2, makron_dead);
+
+ static mframe_t makron_frames_death3[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t makron_move_death3=
+ new mmove_t(FRAME_death301, FRAME_death320, makron_frames_death3, null);
+
+ static mframe_t makron_frames_sight[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t makron_move_sight=
+ new mmove_t(FRAME_active01, FRAME_active13, makron_frames_sight, makron_run);
+
+ static EntThinkAdapter makronBFG= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+
+ float[] start= { 0, 0, 0 };
+ float[] dir= { 0, 0, 0 };
+ float[] vec= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_MAKRON_BFG],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+ gi.sound(self, CHAN_VOICE, sound_attack_bfg, 1, ATTN_NORM, 0);
+ Monster.monster_fire_bfg(self, start, dir, 50, 300, 100, 300, MZ2_MAKRON_BFG);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter MakronSaveloc= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorCopy(self.enemy.s.origin, self.pos1); //save for aiming the shot
+ self.pos1[2] += self.enemy.viewheight;
+ return true;
+ }
+ };
+
+ // FIXME: He's not firing from the proper Z
+
+ static EntThinkAdapter MakronRailgun= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] start= { 0, 0, 0 };
+ float[] dir= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_MAKRON_RAILGUN_1],
+ forward,
+ right,
+ start);
+
+ // calc direction to where we targted
+ Math3D.VectorSubtract(self.pos1, start, dir);
+ Math3D.VectorNormalize(dir);
+
+ Monster.monster_fire_railgun(self, start, dir, 50, 100, MZ2_MAKRON_RAILGUN_1);
+
+ return true;
+ }
+ };
+
+ // FIXME: This is all wrong. He's not firing at the proper angles.
+
+ static EntThinkAdapter MakronHyperblaster= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] dir= { 0, 0, 0 };
+ float[] vec= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ int flash_number;
+
+ flash_number= MZ2_MAKRON_BLASTER_1 + (self.s.frame - FRAME_attak405);
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[flash_number],
+ forward,
+ right,
+ start);
+
+ if (self.enemy != null) {
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, vec);
+ Math3D.vectoangles(vec, vec);
+ dir[0]= vec[0];
+ } else {
+ dir[0]= 0;
+ }
+ if (self.s.frame <= FRAME_attak413)
+ dir[1]= self.s.angles[1] - 10 * (self.s.frame - FRAME_attak413);
+ else
+ dir[1]= self.s.angles[1] + 10 * (self.s.frame - FRAME_attak421);
+ dir[2]= 0;
+
+ Math3D.AngleVectors(dir, forward, null, null);
+
+ Monster.monster_fire_blaster(self, start, forward, 15, 1000, MZ2_MAKRON_BLASTER_1, EF_BLASTER);
+
+ return true;
+ }
+ };
+
+ static EntPainAdapter makron_pain= new EntPainAdapter() {
+ public void makron_pain(edict_t self, edict_t other, float kick, int damage) {
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ // Lessen the chance of him going into his pain frames
+ if (damage <= 25)
+ if (Lib.random() < 0.2)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (damage <= 40) {
+ gi.sound(self, CHAN_VOICE, sound_pain4, 1, ATTN_NONE, 0);
+ self.monsterinfo.currentmove= makron_move_pain4;
+ } else if (damage <= 110) {
+ gi.sound(self, CHAN_VOICE, sound_pain5, 1, ATTN_NONE, 0);
+ self.monsterinfo.currentmove= makron_move_pain5;
+ } else {
+ if (damage <= 150)
+ if (Lib.random() <= 0.45) {
+ gi.sound(self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE, 0);
+ self.monsterinfo.currentmove= makron_move_pain6;
+ } else if (Lib.random() <= 0.35) {
+ gi.sound(self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE, 0);
+ self.monsterinfo.currentmove= makron_move_pain6;
+ }
+ }
+ }
+
+ };
+
+ static EntInteractAdapter makron_sight= new EntInteractAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= makron_move_sight;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] vec= { 0, 0, 0 };
+ float range;
+ float r;
+
+ r= Lib.random();
+
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, vec);
+ range= Math3D.VectorLength(vec);
+
+ if (r <= 0.3)
+ self.monsterinfo.currentmove= makron_move_attack3;
+ else if (r <= 0.6)
+ self.monsterinfo.currentmove= makron_move_attack4;
+ else
+ self.monsterinfo.currentmove= makron_move_attack5;
+
+ return true;
+ }
+ };
+
+ /*
+ ---
+ Makron Torso. This needs to be spawned in
+ ---
+ */
+
+ static EntThinkAdapter makron_torso_think= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (++self.s.frame < 365)
+ self.nextthink= level.time + FRAMETIME;
+ else {
+ self.s.frame= 346;
+ self.nextthink= level.time + FRAMETIME;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter makron_torso= new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ ent.movetype= MOVETYPE_NONE;
+ ent.solid= SOLID_NOT;
+ Math3D.VectorSet(ent.mins, -8, -8, 0);
+ Math3D.VectorSet(ent.maxs, 8, 8, 8);
+ ent.s.frame= 346;
+ ent.s.modelindex= gi.modelindex("models/monsters/boss3/rider/tris.md2");
+ ent.think= makron_torso_think;
+ ent.nextthink= level.time + 2 * FRAMETIME;
+ ent.s.sound= gi.soundindex("makron/spine.wav");
+ gi.linkentity(ent);
+ return true;
+ }
+ };
+
+ static EntDieAdapter makron_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ edict_t tempent;
+
+ int n;
+
+ self.s.sound= 0;
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n= 0; n < 1 /*4*/; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ for (n= 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
+ ThrowHead(self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
+ self.deadflag= DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_YES;
+
+ tempent= G_Spawn();
+ Math3D.VectorCopy(self.s.origin, tempent.s.origin);
+ Math3D.VectorCopy(self.s.angles, tempent.s.angles);
+ tempent.s.origin[1] -= 84;
+ makron_torso.think(tempent);
+
+ self.monsterinfo.currentmove= makron_move_death2;
+ }
+ };
+
+ static EntThinkAdapter Makron_CheckAttack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] spot1= { 0, 0, 0 }, spot2= { 0, 0, 0 };
+ float[] temp= { 0, 0, 0 };
+ float chance;
+ trace_t tr;
+ boolean enemy_infront;
+ int enemy_range;
+ float enemy_yaw;
+
+ if (self.enemy.health > 0) {
+ // see if any entities are in the way of the shot
+ Math3D.VectorCopy(self.s.origin, spot1);
+ spot1[2] += self.viewheight;
+ Math3D.VectorCopy(self.enemy.s.origin, spot2);
+ spot2[2] += self.enemy.viewheight;
+
+ tr=
+ gi.trace(
+ spot1,
+ null,
+ null,
+ spot2,
+ self,
+ CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA);
+
+ // do we have a clear shot?
+ if (tr.ent != self.enemy)
+ return false;
+ }
+
+ enemy_infront= infront(self, self.enemy);
+ enemy_range= range(self, self.enemy);
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp);
+ enemy_yaw= Math3D.vectoyaw(temp);
+
+ self.ideal_yaw= enemy_yaw;
+
+ // melee attack
+ if (enemy_range == RANGE_MELEE) {
+ if (self.monsterinfo.melee != null)
+ self.monsterinfo.attack_state= AS_MELEE;
+ else
+ self.monsterinfo.attack_state= AS_MISSILE;
+ return true;
+ }
+
+ // missile attack
+ if (null != self.monsterinfo.attack)
+ return false;
+
+ if (level.time < self.monsterinfo.attack_finished)
+ return false;
+
+ if (enemy_range == RANGE_FAR)
+ return false;
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ chance= 0.4f;
+ } else if (enemy_range == RANGE_MELEE) {
+ chance= 0.8f;
+ } else if (enemy_range == RANGE_NEAR) {
+ chance= 0.4f;
+ } else if (enemy_range == RANGE_MID) {
+ chance= 0.2f;
+ } else {
+ return false;
+ }
+
+ if (Lib.random() < chance) {
+ self.monsterinfo.attack_state= AS_MISSILE;
+ self.monsterinfo.attack_finished= level.time + 2 * Lib.random();
+ return true;
+ }
+
+ if ((self.flags & FL_FLY) != 0) {
+ if (Lib.random() < 0.3)
+ self.monsterinfo.attack_state= AS_SLIDING;
+ else
+ self.monsterinfo.attack_state= AS_STRAIGHT;
+ }
+
+ return false;
+ }
+ };
+
+ //
+ // monster_makron
+ //
+
+ static void MakronPrecache() {
+ sound_pain4= gi.soundindex("makron/pain3.wav");
+ sound_pain5= gi.soundindex("makron/pain2.wav");
+ sound_pain6= gi.soundindex("makron/pain1.wav");
+ sound_death= gi.soundindex("makron/death.wav");
+ sound_step_left= gi.soundindex("makron/step1.wav");
+ sound_step_right= gi.soundindex("makron/step2.wav");
+ sound_attack_bfg= gi.soundindex("makron/bfg_fire.wav");
+ sound_brainsplorch= gi.soundindex("makron/brain1.wav");
+ sound_prerailgun= gi.soundindex("makron/rail_up.wav");
+ sound_popup= gi.soundindex("makron/popup.wav");
+ sound_taunt1= gi.soundindex("makron/voice4.wav");
+ sound_taunt2= gi.soundindex("makron/voice3.wav");
+ sound_taunt3= gi.soundindex("makron/voice.wav");
+ sound_hit= gi.soundindex("makron/bhit.wav");
+
+ gi.modelindex("models/monsters/boss3/rider/tris.md2");
+ }
+
+ static mframe_t makron_frames_attack3[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, makronBFG),
+ // FIXME: BFG Attack here
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t makron_move_attack3=
+ new mmove_t(FRAME_attak301, FRAME_attak308, makron_frames_attack3, makron_run);
+
+ static mframe_t makron_frames_attack4[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_move, 0, MakronHyperblaster),
+ // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, MakronHyperblaster), // fire
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t makron_move_attack4=
+ new mmove_t(FRAME_attak401, FRAME_attak426, makron_frames_attack4, makron_run);
+
+ static mframe_t makron_frames_attack5[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, makron_prerailgun),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, MakronSaveloc),
+ new mframe_t(ai_move, 0, MakronRailgun),
+ // Fire railgun
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t makron_move_attack5=
+ new mmove_t(FRAME_attak501, FRAME_attak516, makron_frames_attack5, makron_run);
+
+ /*QUAKED monster_makron (1 .5 0) (-30 -30 0) (30 30 90) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_makron(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ MakronPrecache();
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/boss3/rider/tris.md2");
+ Math3D.VectorSet(self.mins, -30, -30, 0);
+ Math3D.VectorSet(self.maxs, 30, 30, 90);
+
+ self.health= 3000;
+ self.gib_health= -2000;
+ self.mass= 500;
+
+ self.pain= makron_pain;
+ self.die= makron_die;
+ self.monsterinfo.stand= makron_stand;
+ self.monsterinfo.walk= makron_walk;
+ self.monsterinfo.run= makron_run;
+ self.monsterinfo.dodge= null;
+ self.monsterinfo.attack= makron_attack;
+ self.monsterinfo.melee= null;
+ self.monsterinfo.sight= makron_sight;
+ self.monsterinfo.checkattack= Makron_CheckAttack;
+
+ gi.linkentity(self);
+
+ // self.monsterinfo.currentmove = &makron_move_stand;
+ self.monsterinfo.currentmove= makron_move_sight;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+
+ /*
+ =================
+ MakronSpawn
+
+ =================
+ */
+ static EntThinkAdapter MakronSpawn= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] vec= { 0, 0, 0 };
+
+ edict_t player;
+
+ SP_monster_makron(self);
+
+ // jump at player
+ player= level.sight_client;
+ if (player == null)
+ return true;
+
+ Math3D.VectorSubtract(player.s.origin, self.s.origin, vec);
+ self.s.angles[YAW]= Math3D.vectoyaw(vec);
+ Math3D.VectorNormalize(vec);
+ Math3D.VectorMA(vec3_origin, 400, vec, self.velocity);
+ self.velocity[2]= 200;
+ self.groundentity= null;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter MakronToss= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent;
+
+ ent= G_Spawn();
+ ent.nextthink= level.time + 0.8f;
+ ent.think= MakronSpawn;
+ ent.target= self.target;
+ Math3D.VectorCopy(self.s.origin, ent.s.origin);
+ return true;
+ }
+ };
+
+}
diff --git a/src/jake2/game/M_Brain.java b/src/jake2/game/M_Brain.java
new file mode 100644
index 0000000..fa2b444
--- /dev/null
+++ b/src/jake2/game/M_Brain.java
@@ -0,0 +1,944 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Brain.java,v 1.1 2004-07-07 19:59:11 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Brain extends GameWeapon {
+
+ public final static int FRAME_walk101= 0;
+ public final static int FRAME_walk102= 1;
+ public final static int FRAME_walk103= 2;
+ public final static int FRAME_walk104= 3;
+ public final static int FRAME_walk105= 4;
+ public final static int FRAME_walk106= 5;
+ public final static int FRAME_walk107= 6;
+ public final static int FRAME_walk108= 7;
+ public final static int FRAME_walk109= 8;
+ public final static int FRAME_walk110= 9;
+ public final static int FRAME_walk111= 10;
+ public final static int FRAME_walk112= 11;
+ public final static int FRAME_walk113= 12;
+ public final static int FRAME_walk201= 13;
+ public final static int FRAME_walk202= 14;
+ public final static int FRAME_walk203= 15;
+ public final static int FRAME_walk204= 16;
+ public final static int FRAME_walk205= 17;
+ public final static int FRAME_walk206= 18;
+ public final static int FRAME_walk207= 19;
+ public final static int FRAME_walk208= 20;
+ public final static int FRAME_walk209= 21;
+ public final static int FRAME_walk210= 22;
+ public final static int FRAME_walk211= 23;
+ public final static int FRAME_walk212= 24;
+ public final static int FRAME_walk213= 25;
+ public final static int FRAME_walk214= 26;
+ public final static int FRAME_walk215= 27;
+ public final static int FRAME_walk216= 28;
+ public final static int FRAME_walk217= 29;
+ public final static int FRAME_walk218= 30;
+ public final static int FRAME_walk219= 31;
+ public final static int FRAME_walk220= 32;
+ public final static int FRAME_walk221= 33;
+ public final static int FRAME_walk222= 34;
+ public final static int FRAME_walk223= 35;
+ public final static int FRAME_walk224= 36;
+ public final static int FRAME_walk225= 37;
+ public final static int FRAME_walk226= 38;
+ public final static int FRAME_walk227= 39;
+ public final static int FRAME_walk228= 40;
+ public final static int FRAME_walk229= 41;
+ public final static int FRAME_walk230= 42;
+ public final static int FRAME_walk231= 43;
+ public final static int FRAME_walk232= 44;
+ public final static int FRAME_walk233= 45;
+ public final static int FRAME_walk234= 46;
+ public final static int FRAME_walk235= 47;
+ public final static int FRAME_walk236= 48;
+ public final static int FRAME_walk237= 49;
+ public final static int FRAME_walk238= 50;
+ public final static int FRAME_walk239= 51;
+ public final static int FRAME_walk240= 52;
+ public final static int FRAME_attak101= 53;
+ public final static int FRAME_attak102= 54;
+ public final static int FRAME_attak103= 55;
+ public final static int FRAME_attak104= 56;
+ public final static int FRAME_attak105= 57;
+ public final static int FRAME_attak106= 58;
+ public final static int FRAME_attak107= 59;
+ public final static int FRAME_attak108= 60;
+ public final static int FRAME_attak109= 61;
+ public final static int FRAME_attak110= 62;
+ public final static int FRAME_attak111= 63;
+ public final static int FRAME_attak112= 64;
+ public final static int FRAME_attak113= 65;
+ public final static int FRAME_attak114= 66;
+ public final static int FRAME_attak115= 67;
+ public final static int FRAME_attak116= 68;
+ public final static int FRAME_attak117= 69;
+ public final static int FRAME_attak118= 70;
+ public final static int FRAME_attak201= 71;
+ public final static int FRAME_attak202= 72;
+ public final static int FRAME_attak203= 73;
+ public final static int FRAME_attak204= 74;
+ public final static int FRAME_attak205= 75;
+ public final static int FRAME_attak206= 76;
+ public final static int FRAME_attak207= 77;
+ public final static int FRAME_attak208= 78;
+ public final static int FRAME_attak209= 79;
+ public final static int FRAME_attak210= 80;
+ public final static int FRAME_attak211= 81;
+ public final static int FRAME_attak212= 82;
+ public final static int FRAME_attak213= 83;
+ public final static int FRAME_attak214= 84;
+ public final static int FRAME_attak215= 85;
+ public final static int FRAME_attak216= 86;
+ public final static int FRAME_attak217= 87;
+ public final static int FRAME_pain101= 88;
+ public final static int FRAME_pain102= 89;
+ public final static int FRAME_pain103= 90;
+ public final static int FRAME_pain104= 91;
+ public final static int FRAME_pain105= 92;
+ public final static int FRAME_pain106= 93;
+ public final static int FRAME_pain107= 94;
+ public final static int FRAME_pain108= 95;
+ public final static int FRAME_pain109= 96;
+ public final static int FRAME_pain110= 97;
+ public final static int FRAME_pain111= 98;
+ public final static int FRAME_pain112= 99;
+ public final static int FRAME_pain113= 100;
+ public final static int FRAME_pain114= 101;
+ public final static int FRAME_pain115= 102;
+ public final static int FRAME_pain116= 103;
+ public final static int FRAME_pain117= 104;
+ public final static int FRAME_pain118= 105;
+ public final static int FRAME_pain119= 106;
+ public final static int FRAME_pain120= 107;
+ public final static int FRAME_pain121= 108;
+ public final static int FRAME_pain201= 109;
+ public final static int FRAME_pain202= 110;
+ public final static int FRAME_pain203= 111;
+ public final static int FRAME_pain204= 112;
+ public final static int FRAME_pain205= 113;
+ public final static int FRAME_pain206= 114;
+ public final static int FRAME_pain207= 115;
+ public final static int FRAME_pain208= 116;
+ public final static int FRAME_pain301= 117;
+ public final static int FRAME_pain302= 118;
+ public final static int FRAME_pain303= 119;
+ public final static int FRAME_pain304= 120;
+ public final static int FRAME_pain305= 121;
+ public final static int FRAME_pain306= 122;
+ public final static int FRAME_death101= 123;
+ public final static int FRAME_death102= 124;
+ public final static int FRAME_death103= 125;
+ public final static int FRAME_death104= 126;
+ public final static int FRAME_death105= 127;
+ public final static int FRAME_death106= 128;
+ public final static int FRAME_death107= 129;
+ public final static int FRAME_death108= 130;
+ public final static int FRAME_death109= 131;
+ public final static int FRAME_death110= 132;
+ public final static int FRAME_death111= 133;
+ public final static int FRAME_death112= 134;
+ public final static int FRAME_death113= 135;
+ public final static int FRAME_death114= 136;
+ public final static int FRAME_death115= 137;
+ public final static int FRAME_death116= 138;
+ public final static int FRAME_death117= 139;
+ public final static int FRAME_death118= 140;
+ public final static int FRAME_death201= 141;
+ public final static int FRAME_death202= 142;
+ public final static int FRAME_death203= 143;
+ public final static int FRAME_death204= 144;
+ public final static int FRAME_death205= 145;
+ public final static int FRAME_duck01= 146;
+ public final static int FRAME_duck02= 147;
+ public final static int FRAME_duck03= 148;
+ public final static int FRAME_duck04= 149;
+ public final static int FRAME_duck05= 150;
+ public final static int FRAME_duck06= 151;
+ public final static int FRAME_duck07= 152;
+ public final static int FRAME_duck08= 153;
+ public final static int FRAME_defens01= 154;
+ public final static int FRAME_defens02= 155;
+ public final static int FRAME_defens03= 156;
+ public final static int FRAME_defens04= 157;
+ public final static int FRAME_defens05= 158;
+ public final static int FRAME_defens06= 159;
+ public final static int FRAME_defens07= 160;
+ public final static int FRAME_defens08= 161;
+ public final static int FRAME_stand01= 162;
+ public final static int FRAME_stand02= 163;
+ public final static int FRAME_stand03= 164;
+ public final static int FRAME_stand04= 165;
+ public final static int FRAME_stand05= 166;
+ public final static int FRAME_stand06= 167;
+ public final static int FRAME_stand07= 168;
+ public final static int FRAME_stand08= 169;
+ public final static int FRAME_stand09= 170;
+ public final static int FRAME_stand10= 171;
+ public final static int FRAME_stand11= 172;
+ public final static int FRAME_stand12= 173;
+ public final static int FRAME_stand13= 174;
+ public final static int FRAME_stand14= 175;
+ public final static int FRAME_stand15= 176;
+ public final static int FRAME_stand16= 177;
+ public final static int FRAME_stand17= 178;
+ public final static int FRAME_stand18= 179;
+ public final static int FRAME_stand19= 180;
+ public final static int FRAME_stand20= 181;
+ public final static int FRAME_stand21= 182;
+ public final static int FRAME_stand22= 183;
+ public final static int FRAME_stand23= 184;
+ public final static int FRAME_stand24= 185;
+ public final static int FRAME_stand25= 186;
+ public final static int FRAME_stand26= 187;
+ public final static int FRAME_stand27= 188;
+ public final static int FRAME_stand28= 189;
+ public final static int FRAME_stand29= 190;
+ public final static int FRAME_stand30= 191;
+ public final static int FRAME_stand31= 192;
+ public final static int FRAME_stand32= 193;
+ public final static int FRAME_stand33= 194;
+ public final static int FRAME_stand34= 195;
+ public final static int FRAME_stand35= 196;
+ public final static int FRAME_stand36= 197;
+ public final static int FRAME_stand37= 198;
+ public final static int FRAME_stand38= 199;
+ public final static int FRAME_stand39= 200;
+ public final static int FRAME_stand40= 201;
+ public final static int FRAME_stand41= 202;
+ public final static int FRAME_stand42= 203;
+ public final static int FRAME_stand43= 204;
+ public final static int FRAME_stand44= 205;
+ public final static int FRAME_stand45= 206;
+ public final static int FRAME_stand46= 207;
+ public final static int FRAME_stand47= 208;
+ public final static int FRAME_stand48= 209;
+ public final static int FRAME_stand49= 210;
+ public final static int FRAME_stand50= 211;
+ public final static int FRAME_stand51= 212;
+ public final static int FRAME_stand52= 213;
+ public final static int FRAME_stand53= 214;
+ public final static int FRAME_stand54= 215;
+ public final static int FRAME_stand55= 216;
+ public final static int FRAME_stand56= 217;
+ public final static int FRAME_stand57= 218;
+ public final static int FRAME_stand58= 219;
+ public final static int FRAME_stand59= 220;
+ public final static int FRAME_stand60= 221;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_chest_open;
+ static int sound_tentacles_extend;
+ static int sound_tentacles_retract;
+ static int sound_death;
+ static int sound_idle1;
+ static int sound_idle2;
+ static int sound_idle3;
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_sight;
+ static int sound_search;
+ static int sound_melee1;
+ static int sound_melee2;
+ static int sound_melee3;
+
+ static EntInteractAdapter brain_sight= new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_search= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ //
+ // STAND
+ //
+
+ static mframe_t brain_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t brain_move_stand=
+ new mmove_t(FRAME_stand01, FRAME_stand30, brain_frames_stand, null);
+
+ static EntThinkAdapter brain_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= brain_move_stand;
+ return true;
+ }
+ };
+
+ //
+ // IDLE
+ //
+
+ static mframe_t brain_frames_idle[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t brain_move_idle=
+ new mmove_t(FRAME_stand31, FRAME_stand60, brain_frames_idle, brain_stand);
+
+ /*
+ static EntThinkAdapter xxx = new EntThinkAdapter()
+ {
+ public boolean think(edict_t self)
+ {
+ return true;
+ }
+ };
+ */
+
+ static EntThinkAdapter brain_idle= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_AUTO, sound_idle3, 1, ATTN_IDLE, 0);
+ self.monsterinfo.currentmove= brain_move_idle;
+ return true;
+ }
+ };
+
+ //
+ // WALK
+ //
+ static mframe_t brain_frames_walk1[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, -4, null),
+ new mframe_t(ai_walk, -1, null),
+ new mframe_t(ai_walk, 2, null)};
+ static mmove_t brain_move_walk1=
+ new mmove_t(FRAME_walk101, FRAME_walk111, brain_frames_walk1, null);
+
+ // walk2 is FUBAR, do not use
+ /*
+ # if 0
+ void brain_walk2_cycle(edict_t self)
+ {
+ if (random() > 0.1)
+ self.monsterinfo.nextframe= FRAME_walk220;
+ }
+
+ static mframe_t brain_frames_walk2[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, -2, null),
+ new mframe_t(ai_walk, -4, null),
+ new mframe_t(ai_walk, -3, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 12, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, -3, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, -2, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 10, null, // Cycle Start)
+
+ new mframe_t(ai_walk, -1, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, -3, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, -3, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 4, brain_walk2_cycle),
+ new mframe_t(ai_walk, -1, null),
+ new mframe_t(ai_walk, -1, null),
+ new mframe_t(ai_walk, -8, null,) new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, -1, null),
+ new mframe_t(ai_walk, -5, null)};
+ static mmove_t brain_move_walk2=
+ new mmove_t(FRAME_walk201, FRAME_walk240, brain_frames_walk2, null);
+
+ # endif
+ */
+ static EntThinkAdapter brain_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ // if (random() <= 0.5)
+ self.monsterinfo.currentmove= brain_move_walk1;
+ // else
+ // self.monsterinfo.currentmove = &brain_move_walk2;
+ return true;
+ }
+ };
+
+ //
+ // DUCK
+ //
+
+ static EntThinkAdapter brain_duck_down= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if ((self.monsterinfo.aiflags & AI_DUCKED) != 0)
+ return true;
+ self.monsterinfo.aiflags |= AI_DUCKED;
+ self.maxs[2] -= 32;
+ self.takedamage= DAMAGE_YES;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_duck_hold= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_duck_up= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.aiflags &= ~AI_DUCKED;
+ self.maxs[2] += 32;
+ self.takedamage= DAMAGE_AIM;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntDodgeAdapter brain_dodge= new EntDodgeAdapter() {
+ public boolean brain_dodge(edict_t self, edict_t attacker, float eta) {
+ if (Lib.random() > 0.25)
+ return true;
+
+ if (self.enemy == null)
+ self.enemy= attacker;
+
+ self.monsterinfo.pausetime= level.time + eta + 0.5f;
+ self.monsterinfo.currentmove= brain_move_duck;
+ return true;
+ }
+ };
+
+ static mframe_t brain_frames_death2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 9, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static EntThinkAdapter brain_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mmove_t brain_move_death2=
+ new mmove_t(FRAME_death201, FRAME_death205, brain_frames_death2, brain_dead);
+
+ static mframe_t brain_frames_death1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 9, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t brain_move_death1=
+ new mmove_t(FRAME_death101, FRAME_death118, brain_frames_death1, brain_dead);
+
+ //
+ // MELEE
+ //
+
+ static EntThinkAdapter brain_swing_right= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_melee1, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_hit_right= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim= { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.maxs[0], 8);
+ if (Fire.fire_hit(self, aim, (15 + (Lib.rand() % 5)), 40))
+ gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter xxx= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_swing_left= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_melee2, 1, ATTN_NORM, 0);
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_hit_left= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim= { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.mins[0], 8);
+ if (Fire.fire_hit(self, aim, (15 + (Lib.rand() % 5)), 40))
+ gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0);
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_chest_open= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.spawnflags &= ~65536;
+ self.monsterinfo.power_armor_type= POWER_ARMOR_NONE;
+ gi.sound(self, CHAN_BODY, sound_chest_open, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter brain_tentacle_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] aim= { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, 0, 8);
+ if (Fire.fire_hit(self, aim, (10 + (Lib.rand() % 5)), -600) && skill.value > 0)
+ self.spawnflags |= 65536;
+ gi.sound(self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t brain_frames_attack1[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 8, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -3, brain_swing_right),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -5, null),
+ new mframe_t(ai_charge, -7, brain_hit_right),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 6, brain_swing_left),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 2, brain_hit_left),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 6, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, -11, null)};
+
+ static EntThinkAdapter brain_chest_closed= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.monsterinfo.power_armor_type= POWER_ARMOR_SCREEN;
+ if ((self.spawnflags & 65536) != 0) {
+ self.spawnflags &= ~65536;
+ self.monsterinfo.currentmove= brain_move_attack1;
+ }
+ return true;
+ }
+ };
+
+ static mframe_t brain_frames_attack2[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, -4, null),
+ new mframe_t(ai_charge, -4, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 0, brain_chest_open),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 13, brain_tentacle_attack),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -9, brain_chest_closed),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, -6, null)};
+
+ static EntThinkAdapter brain_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() <= 0.5)
+ self.monsterinfo.currentmove= brain_move_attack1;
+ else
+ self.monsterinfo.currentmove= brain_move_attack2;
+
+ return true;
+ }
+ };
+
+ //
+ // RUN
+ //
+
+ static mframe_t brain_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 2, null),
+ new mframe_t(ai_run, 3, null),
+ new mframe_t(ai_run, 3, null),
+ new mframe_t(ai_run, 1, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, -4, null),
+ new mframe_t(ai_run, -1, null),
+ new mframe_t(ai_run, 2, null)};
+
+ static mmove_t brain_move_run=
+ new mmove_t(FRAME_walk101, FRAME_walk111, brain_frames_run, null);
+
+ static EntThinkAdapter brain_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.power_armor_type= POWER_ARMOR_SCREEN;
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove= brain_move_stand;
+ else
+ self.monsterinfo.currentmove= brain_move_run;
+ return true;
+ }
+ };
+
+ static mframe_t brain_frames_defense[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t brain_move_defense=
+ new mmove_t(FRAME_defens01, FRAME_defens08, brain_frames_defense, null);
+
+ static mframe_t brain_frames_pain3[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -4, null)};
+ static mmove_t brain_move_pain3=
+ new mmove_t(FRAME_pain301, FRAME_pain306, brain_frames_pain3, brain_run);
+
+ static mframe_t brain_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, -2, null)};
+ static mmove_t brain_move_pain2=
+ new mmove_t(FRAME_pain201, FRAME_pain208, brain_frames_pain2, brain_run);
+
+ static mframe_t brain_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 7, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, -1, null)};
+
+ static mmove_t brain_move_pain1=
+ new mmove_t(FRAME_pain101, FRAME_pain121, brain_frames_pain1, brain_run);
+
+ static mframe_t brain_frames_duck[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, brain_duck_down),
+ new mframe_t(ai_move, 17, brain_duck_hold),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -1, brain_duck_up),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -6, null)};
+
+ static mmove_t brain_move_duck=
+ new mmove_t(FRAME_duck01, FRAME_duck08, brain_frames_duck, brain_run);
+
+ static EntPainAdapter brain_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ float r;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ r= Lib.random();
+ if (r < 0.33) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= brain_move_pain1;
+ } else if (r < 0.66) {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= brain_move_pain2;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= brain_move_pain3;
+ }
+ }
+
+ };
+
+ static EntDieAdapter brain_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ int n;
+
+ self.s.effects= 0;
+ self.monsterinfo.power_armor_type= POWER_ARMOR_NONE;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n= 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n= 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag= DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_YES;
+ if (Lib.random() <= 0.5)
+ self.monsterinfo.currentmove= brain_move_death1;
+ else
+ self.monsterinfo.currentmove= brain_move_death2;
+ }
+ };
+
+ static mmove_t brain_move_attack1=
+ new mmove_t(FRAME_attak101, FRAME_attak118, brain_frames_attack1, brain_run);
+ static mmove_t brain_move_attack2=
+ new mmove_t(FRAME_attak201, FRAME_attak217, brain_frames_attack2, brain_run);
+
+ /*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_brain(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_chest_open= gi.soundindex("brain/brnatck1.wav");
+ sound_tentacles_extend= gi.soundindex("brain/brnatck2.wav");
+ sound_tentacles_retract= gi.soundindex("brain/brnatck3.wav");
+ sound_death= gi.soundindex("brain/brndeth1.wav");
+ sound_idle1= gi.soundindex("brain/brnidle1.wav");
+ sound_idle2= gi.soundindex("brain/brnidle2.wav");
+ sound_idle3= gi.soundindex("brain/brnlens1.wav");
+ sound_pain1= gi.soundindex("brain/brnpain1.wav");
+ sound_pain2= gi.soundindex("brain/brnpain2.wav");
+ sound_sight= gi.soundindex("brain/brnsght1.wav");
+ sound_search= gi.soundindex("brain/brnsrch1.wav");
+ sound_melee1= gi.soundindex("brain/melee1.wav");
+ sound_melee2= gi.soundindex("brain/melee2.wav");
+ sound_melee3= gi.soundindex("brain/melee3.wav");
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/brain/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+
+ self.health= 300;
+ self.gib_health= -150;
+ self.mass= 400;
+
+ self.pain= brain_pain;
+ self.die= brain_die;
+
+ self.monsterinfo.stand= brain_stand;
+ self.monsterinfo.walk= brain_walk;
+ self.monsterinfo.run= brain_run;
+ self.monsterinfo.dodge= brain_dodge;
+ // self.monsterinfo.attack = brain_attack;
+ self.monsterinfo.melee= brain_melee;
+ self.monsterinfo.sight= brain_sight;
+ self.monsterinfo.search= brain_search;
+ self.monsterinfo.idle= brain_idle;
+
+ self.monsterinfo.power_armor_type= POWER_ARMOR_SCREEN;
+ self.monsterinfo.power_armor_power= 100;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove= brain_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+}
diff --git a/src/jake2/game/M_Chick.java b/src/jake2/game/M_Chick.java
new file mode 100644
index 0000000..0fd006c
--- /dev/null
+++ b/src/jake2/game/M_Chick.java
@@ -0,0 +1,987 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Chick.java,v 1.1 2004-07-07 19:59:11 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Chick extends GameWeapon {
+
+ public final static int FRAME_attak101= 0;
+ public final static int FRAME_attak102= 1;
+ public final static int FRAME_attak103= 2;
+ public final static int FRAME_attak104= 3;
+ public final static int FRAME_attak105= 4;
+ public final static int FRAME_attak106= 5;
+ public final static int FRAME_attak107= 6;
+ public final static int FRAME_attak108= 7;
+ public final static int FRAME_attak109= 8;
+ public final static int FRAME_attak110= 9;
+ public final static int FRAME_attak111= 10;
+ public final static int FRAME_attak112= 11;
+ public final static int FRAME_attak113= 12;
+ public final static int FRAME_attak114= 13;
+ public final static int FRAME_attak115= 14;
+ public final static int FRAME_attak116= 15;
+ public final static int FRAME_attak117= 16;
+ public final static int FRAME_attak118= 17;
+ public final static int FRAME_attak119= 18;
+ public final static int FRAME_attak120= 19;
+ public final static int FRAME_attak121= 20;
+ public final static int FRAME_attak122= 21;
+ public final static int FRAME_attak123= 22;
+ public final static int FRAME_attak124= 23;
+ public final static int FRAME_attak125= 24;
+ public final static int FRAME_attak126= 25;
+ public final static int FRAME_attak127= 26;
+ public final static int FRAME_attak128= 27;
+ public final static int FRAME_attak129= 28;
+ public final static int FRAME_attak130= 29;
+ public final static int FRAME_attak131= 30;
+ public final static int FRAME_attak132= 31;
+ public final static int FRAME_attak201= 32;
+ public final static int FRAME_attak202= 33;
+ public final static int FRAME_attak203= 34;
+ public final static int FRAME_attak204= 35;
+ public final static int FRAME_attak205= 36;
+ public final static int FRAME_attak206= 37;
+ public final static int FRAME_attak207= 38;
+ public final static int FRAME_attak208= 39;
+ public final static int FRAME_attak209= 40;
+ public final static int FRAME_attak210= 41;
+ public final static int FRAME_attak211= 42;
+ public final static int FRAME_attak212= 43;
+ public final static int FRAME_attak213= 44;
+ public final static int FRAME_attak214= 45;
+ public final static int FRAME_attak215= 46;
+ public final static int FRAME_attak216= 47;
+ public final static int FRAME_death101= 48;
+ public final static int FRAME_death102= 49;
+ public final static int FRAME_death103= 50;
+ public final static int FRAME_death104= 51;
+ public final static int FRAME_death105= 52;
+ public final static int FRAME_death106= 53;
+ public final static int FRAME_death107= 54;
+ public final static int FRAME_death108= 55;
+ public final static int FRAME_death109= 56;
+ public final static int FRAME_death110= 57;
+ public final static int FRAME_death111= 58;
+ public final static int FRAME_death112= 59;
+ public final static int FRAME_death201= 60;
+ public final static int FRAME_death202= 61;
+ public final static int FRAME_death203= 62;
+ public final static int FRAME_death204= 63;
+ public final static int FRAME_death205= 64;
+ public final static int FRAME_death206= 65;
+ public final static int FRAME_death207= 66;
+ public final static int FRAME_death208= 67;
+ public final static int FRAME_death209= 68;
+ public final static int FRAME_death210= 69;
+ public final static int FRAME_death211= 70;
+ public final static int FRAME_death212= 71;
+ public final static int FRAME_death213= 72;
+ public final static int FRAME_death214= 73;
+ public final static int FRAME_death215= 74;
+ public final static int FRAME_death216= 75;
+ public final static int FRAME_death217= 76;
+ public final static int FRAME_death218= 77;
+ public final static int FRAME_death219= 78;
+ public final static int FRAME_death220= 79;
+ public final static int FRAME_death221= 80;
+ public final static int FRAME_death222= 81;
+ public final static int FRAME_death223= 82;
+ public final static int FRAME_duck01= 83;
+ public final static int FRAME_duck02= 84;
+ public final static int FRAME_duck03= 85;
+ public final static int FRAME_duck04= 86;
+ public final static int FRAME_duck05= 87;
+ public final static int FRAME_duck06= 88;
+ public final static int FRAME_duck07= 89;
+ public final static int FRAME_pain101= 90;
+ public final static int FRAME_pain102= 91;
+ public final static int FRAME_pain103= 92;
+ public final static int FRAME_pain104= 93;
+ public final static int FRAME_pain105= 94;
+ public final static int FRAME_pain201= 95;
+ public final static int FRAME_pain202= 96;
+ public final static int FRAME_pain203= 97;
+ public final static int FRAME_pain204= 98;
+ public final static int FRAME_pain205= 99;
+ public final static int FRAME_pain301= 100;
+ public final static int FRAME_pain302= 101;
+ public final static int FRAME_pain303= 102;
+ public final static int FRAME_pain304= 103;
+ public final static int FRAME_pain305= 104;
+ public final static int FRAME_pain306= 105;
+ public final static int FRAME_pain307= 106;
+ public final static int FRAME_pain308= 107;
+ public final static int FRAME_pain309= 108;
+ public final static int FRAME_pain310= 109;
+ public final static int FRAME_pain311= 110;
+ public final static int FRAME_pain312= 111;
+ public final static int FRAME_pain313= 112;
+ public final static int FRAME_pain314= 113;
+ public final static int FRAME_pain315= 114;
+ public final static int FRAME_pain316= 115;
+ public final static int FRAME_pain317= 116;
+ public final static int FRAME_pain318= 117;
+ public final static int FRAME_pain319= 118;
+ public final static int FRAME_pain320= 119;
+ public final static int FRAME_pain321= 120;
+ public final static int FRAME_stand101= 121;
+ public final static int FRAME_stand102= 122;
+ public final static int FRAME_stand103= 123;
+ public final static int FRAME_stand104= 124;
+ public final static int FRAME_stand105= 125;
+ public final static int FRAME_stand106= 126;
+ public final static int FRAME_stand107= 127;
+ public final static int FRAME_stand108= 128;
+ public final static int FRAME_stand109= 129;
+ public final static int FRAME_stand110= 130;
+ public final static int FRAME_stand111= 131;
+ public final static int FRAME_stand112= 132;
+ public final static int FRAME_stand113= 133;
+ public final static int FRAME_stand114= 134;
+ public final static int FRAME_stand115= 135;
+ public final static int FRAME_stand116= 136;
+ public final static int FRAME_stand117= 137;
+ public final static int FRAME_stand118= 138;
+ public final static int FRAME_stand119= 139;
+ public final static int FRAME_stand120= 140;
+ public final static int FRAME_stand121= 141;
+ public final static int FRAME_stand122= 142;
+ public final static int FRAME_stand123= 143;
+ public final static int FRAME_stand124= 144;
+ public final static int FRAME_stand125= 145;
+ public final static int FRAME_stand126= 146;
+ public final static int FRAME_stand127= 147;
+ public final static int FRAME_stand128= 148;
+ public final static int FRAME_stand129= 149;
+ public final static int FRAME_stand130= 150;
+ public final static int FRAME_stand201= 151;
+ public final static int FRAME_stand202= 152;
+ public final static int FRAME_stand203= 153;
+ public final static int FRAME_stand204= 154;
+ public final static int FRAME_stand205= 155;
+ public final static int FRAME_stand206= 156;
+ public final static int FRAME_stand207= 157;
+ public final static int FRAME_stand208= 158;
+ public final static int FRAME_stand209= 159;
+ public final static int FRAME_stand210= 160;
+ public final static int FRAME_stand211= 161;
+ public final static int FRAME_stand212= 162;
+ public final static int FRAME_stand213= 163;
+ public final static int FRAME_stand214= 164;
+ public final static int FRAME_stand215= 165;
+ public final static int FRAME_stand216= 166;
+ public final static int FRAME_stand217= 167;
+ public final static int FRAME_stand218= 168;
+ public final static int FRAME_stand219= 169;
+ public final static int FRAME_stand220= 170;
+ public final static int FRAME_stand221= 171;
+ public final static int FRAME_stand222= 172;
+ public final static int FRAME_stand223= 173;
+ public final static int FRAME_stand224= 174;
+ public final static int FRAME_stand225= 175;
+ public final static int FRAME_stand226= 176;
+ public final static int FRAME_stand227= 177;
+ public final static int FRAME_stand228= 178;
+ public final static int FRAME_stand229= 179;
+ public final static int FRAME_stand230= 180;
+ public final static int FRAME_walk01= 181;
+ public final static int FRAME_walk02= 182;
+ public final static int FRAME_walk03= 183;
+ public final static int FRAME_walk04= 184;
+ public final static int FRAME_walk05= 185;
+ public final static int FRAME_walk06= 186;
+ public final static int FRAME_walk07= 187;
+ public final static int FRAME_walk08= 188;
+ public final static int FRAME_walk09= 189;
+ public final static int FRAME_walk10= 190;
+ public final static int FRAME_walk11= 191;
+ public final static int FRAME_walk12= 192;
+ public final static int FRAME_walk13= 193;
+ public final static int FRAME_walk14= 194;
+ public final static int FRAME_walk15= 195;
+ public final static int FRAME_walk16= 196;
+ public final static int FRAME_walk17= 197;
+ public final static int FRAME_walk18= 198;
+ public final static int FRAME_walk19= 199;
+ public final static int FRAME_walk20= 200;
+ public final static int FRAME_walk21= 201;
+ public final static int FRAME_walk22= 202;
+ public final static int FRAME_walk23= 203;
+ public final static int FRAME_walk24= 204;
+ public final static int FRAME_walk25= 205;
+ public final static int FRAME_walk26= 206;
+ public final static int FRAME_walk27= 207;
+ public final static int FRAME_recln201= 208;
+ public final static int FRAME_recln202= 209;
+ public final static int FRAME_recln203= 210;
+ public final static int FRAME_recln204= 211;
+ public final static int FRAME_recln205= 212;
+ public final static int FRAME_recln206= 213;
+ public final static int FRAME_recln207= 214;
+ public final static int FRAME_recln208= 215;
+ public final static int FRAME_recln209= 216;
+ public final static int FRAME_recln210= 217;
+ public final static int FRAME_recln211= 218;
+ public final static int FRAME_recln212= 219;
+ public final static int FRAME_recln213= 220;
+ public final static int FRAME_recln214= 221;
+ public final static int FRAME_recln215= 222;
+ public final static int FRAME_recln216= 223;
+ public final static int FRAME_recln217= 224;
+ public final static int FRAME_recln218= 225;
+ public final static int FRAME_recln219= 226;
+ public final static int FRAME_recln220= 227;
+ public final static int FRAME_recln221= 228;
+ public final static int FRAME_recln222= 229;
+ public final static int FRAME_recln223= 230;
+ public final static int FRAME_recln224= 231;
+ public final static int FRAME_recln225= 232;
+ public final static int FRAME_recln226= 233;
+ public final static int FRAME_recln227= 234;
+ public final static int FRAME_recln228= 235;
+ public final static int FRAME_recln229= 236;
+ public final static int FRAME_recln230= 237;
+ public final static int FRAME_recln231= 238;
+ public final static int FRAME_recln232= 239;
+ public final static int FRAME_recln233= 240;
+ public final static int FRAME_recln234= 241;
+ public final static int FRAME_recln235= 242;
+ public final static int FRAME_recln236= 243;
+ public final static int FRAME_recln237= 244;
+ public final static int FRAME_recln238= 245;
+ public final static int FRAME_recln239= 246;
+ public final static int FRAME_recln240= 247;
+ public final static int FRAME_recln101= 248;
+ public final static int FRAME_recln102= 249;
+ public final static int FRAME_recln103= 250;
+ public final static int FRAME_recln104= 251;
+ public final static int FRAME_recln105= 252;
+ public final static int FRAME_recln106= 253;
+ public final static int FRAME_recln107= 254;
+ public final static int FRAME_recln108= 255;
+ public final static int FRAME_recln109= 256;
+ public final static int FRAME_recln110= 257;
+ public final static int FRAME_recln111= 258;
+ public final static int FRAME_recln112= 259;
+ public final static int FRAME_recln113= 260;
+ public final static int FRAME_recln114= 261;
+ public final static int FRAME_recln115= 262;
+ public final static int FRAME_recln116= 263;
+ public final static int FRAME_recln117= 264;
+ public final static int FRAME_recln118= 265;
+ public final static int FRAME_recln119= 266;
+ public final static int FRAME_recln120= 267;
+ public final static int FRAME_recln121= 268;
+ public final static int FRAME_recln122= 269;
+ public final static int FRAME_recln123= 270;
+ public final static int FRAME_recln124= 271;
+ public final static int FRAME_recln125= 272;
+ public final static int FRAME_recln126= 273;
+ public final static int FRAME_recln127= 274;
+ public final static int FRAME_recln128= 275;
+ public final static int FRAME_recln129= 276;
+ public final static int FRAME_recln130= 277;
+ public final static int FRAME_recln131= 278;
+ public final static int FRAME_recln132= 279;
+ public final static int FRAME_recln133= 280;
+ public final static int FRAME_recln134= 281;
+ public final static int FRAME_recln135= 282;
+ public final static int FRAME_recln136= 283;
+ public final static int FRAME_recln137= 284;
+ public final static int FRAME_recln138= 285;
+ public final static int FRAME_recln139= 286;
+ public final static int FRAME_recln140= 287;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_missile_prelaunch;
+ static int sound_missile_launch;
+ static int sound_melee_swing;
+ static int sound_melee_hit;
+ static int sound_missile_reload;
+ static int sound_death1;
+ static int sound_death2;
+ static int sound_fall_down;
+ static int sound_idle1;
+ static int sound_idle2;
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_pain3;
+ static int sound_sight;
+ static int sound_search;
+
+ static EntThinkAdapter ChickMoan= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_idle2, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_fidget[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, ChickMoan),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static EntThinkAdapter chick_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= chick_move_stand;
+ return true;
+ }
+ };
+ static mmove_t chick_move_fidget=
+ new mmove_t(FRAME_stand201, FRAME_stand230, chick_frames_fidget, chick_stand);
+
+ static EntThinkAdapter chick_fidget= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ return true;
+ if (Lib.random() <= 0.3)
+ self.monsterinfo.currentmove= chick_move_fidget;
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, chick_fidget),
+ };
+ static mmove_t chick_move_stand=
+ new mmove_t(FRAME_stand101, FRAME_stand130, chick_frames_stand, null);
+
+ static EntThinkAdapter chick_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ self.monsterinfo.currentmove= chick_move_stand;
+ return true;
+ }
+
+ if (self.monsterinfo.currentmove == chick_move_walk
+ || self.monsterinfo.currentmove == chick_move_start_run) {
+ self.monsterinfo.currentmove= chick_move_run;
+ } else {
+ self.monsterinfo.currentmove= chick_move_start_run;
+ }
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_start_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 1, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, -1, null),
+ new mframe_t(ai_run, -1, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 1, null),
+ new mframe_t(ai_run, 3, null),
+ new mframe_t(ai_run, 6, null),
+ new mframe_t(ai_run, 3, null)};
+ static mmove_t chick_move_start_run=
+ new mmove_t(FRAME_walk01, FRAME_walk10, chick_frames_start_run, chick_run);
+
+ static mframe_t chick_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 6, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 7, null),
+ new mframe_t(ai_run, 4, null),
+ new mframe_t(ai_run, 11, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 7, null)};
+
+ static mmove_t chick_move_run= new mmove_t(FRAME_walk11, FRAME_walk20, chick_frames_run, null);
+
+ static mframe_t chick_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 13, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 11, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 7, null)};
+
+ static mmove_t chick_move_walk=
+ new mmove_t(FRAME_walk11, FRAME_walk20, chick_frames_walk, null);
+
+ static EntThinkAdapter chick_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= chick_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t chick_move_pain1=
+ new mmove_t(FRAME_pain101, FRAME_pain105, chick_frames_pain1, chick_run);
+
+ static mframe_t chick_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t chick_move_pain2=
+ new mmove_t(FRAME_pain201, FRAME_pain205, chick_frames_pain2, chick_run);
+
+ static mframe_t chick_frames_pain3[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 11, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, 7, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -8, null),
+ new mframe_t(ai_move, 2, null)};
+
+ static mmove_t chick_move_pain3=
+ new mmove_t(FRAME_pain301, FRAME_pain321, chick_frames_pain3, chick_run);
+
+ static EntPainAdapter chick_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ float r;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+
+ r= Lib.random();
+ if (r < 0.33)
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ else if (r < 0.66)
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (damage <= 10)
+ self.monsterinfo.currentmove= chick_move_pain1;
+ else if (damage <= 25)
+ self.monsterinfo.currentmove= chick_move_pain2;
+ else
+ self.monsterinfo.currentmove= chick_move_pain3;
+ return;
+ }
+ };
+
+ static EntThinkAdapter chick_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, 0);
+ Math3D.VectorSet(self.maxs, 16, 16, 16);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_death2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 10, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 15, null),
+ new mframe_t(ai_move, 14, null),
+ new mframe_t(ai_move, 1, null)};
+ static mmove_t chick_move_death2=
+ new mmove_t(FRAME_death201, FRAME_death223, chick_frames_death2, chick_dead);
+
+ static mframe_t chick_frames_death1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 11, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t chick_move_death1=
+ new mmove_t(FRAME_death101, FRAME_death112, chick_frames_death1, chick_dead);
+
+ static EntDieAdapter chick_die= new EntDieAdapter() {
+
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n= 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n= 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag= DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_YES;
+
+ n= Lib.rand() % 2;
+ if (n == 0) {
+ self.monsterinfo.currentmove= chick_move_death1;
+ gi.sound(self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
+ } else {
+ self.monsterinfo.currentmove= chick_move_death2;
+ gi.sound(self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
+ }
+ }
+
+ };
+ static EntThinkAdapter chick_duck_down= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_DUCKED) != 0)
+ return true;
+ self.monsterinfo.aiflags |= AI_DUCKED;
+ self.maxs[2] -= 32;
+ self.takedamage= DAMAGE_YES;
+ self.monsterinfo.pausetime= level.time + 1;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter chick_duck_hold= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter chick_duck_up= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.aiflags &= ~AI_DUCKED;
+ self.maxs[2] += 32;
+ self.takedamage= DAMAGE_AIM;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_duck[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, chick_duck_down),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 4, chick_duck_hold),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -5, chick_duck_up),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 1, null)};
+ static mmove_t chick_move_duck=
+ new mmove_t(FRAME_duck01, FRAME_duck07, chick_frames_duck, chick_run);
+
+ static EntDodgeAdapter chick_dodge= new EntDodgeAdapter() {
+ public void dodge(edict_t self, edict_t attacker, float eta) {
+ if (Lib.random() > 0.25)
+ return;
+
+ if (self.enemy != null)
+ self.enemy= attacker;
+
+ self.monsterinfo.currentmove= chick_move_duck;
+ return;
+ }
+ };
+
+ static EntThinkAdapter ChickSlash= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim= { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.mins[0], 10);
+ gi.sound(self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0);
+ Fire.fire_hit(self, aim, (10 + (Lib.rand() % 6)), 100);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter ChickRocket= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+ float[] start= { 0, 0, 0 };
+ float[] dir= { 0, 0, 0 };
+ float[] vec= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_CHICK_ROCKET_1],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+
+ Monster.monster_fire_rocket(self, start, dir, 50, 500, MZ2_CHICK_ROCKET_1);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter Chick_PreAttack1= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_missile_prelaunch, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter ChickReload= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_missile_reload, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+ static EntThinkAdapter chick_attack1= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= chick_move_attack1;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter chick_rerocket= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.enemy.health > 0) {
+ if (range(self, self.enemy) > RANGE_MELEE)
+ if (visible(self, self.enemy))
+ if (Lib.random() <= 0.6) {
+ self.monsterinfo.currentmove= chick_move_attack1;
+ return true;
+ }
+ }
+ self.monsterinfo.currentmove= chick_move_end_attack1;
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_start_attack1[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, Chick_PreAttack1),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, 7, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, chick_attack1)};
+ static mmove_t chick_move_start_attack1=
+ new mmove_t(FRAME_attak101, FRAME_attak113, chick_frames_start_attack1, null);
+
+ static mframe_t chick_frames_attack1[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 19, ChickRocket),
+ new mframe_t(ai_charge, -6, null),
+ new mframe_t(ai_charge, -5, null),
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, -7, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 10, ChickReload),
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, 6, null),
+ new mframe_t(ai_charge, 6, null),
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 3, chick_rerocket)};
+ static mmove_t chick_move_attack1=
+ new mmove_t(FRAME_attak114, FRAME_attak127, chick_frames_attack1, null);
+
+ static mframe_t chick_frames_end_attack1[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -6, null),
+ new mframe_t(ai_charge, -4, null),
+ new mframe_t(ai_charge, -2, null)};
+ static mmove_t chick_move_end_attack1=
+ new mmove_t(FRAME_attak128, FRAME_attak132, chick_frames_end_attack1, chick_run);
+
+ static EntThinkAdapter chick_reslash= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.enemy.health > 0) {
+ if (range(self, self.enemy) == RANGE_MELEE)
+ if (Lib.random() <= 0.9) {
+ self.monsterinfo.currentmove= chick_move_slash;
+ return true;
+ } else {
+ self.monsterinfo.currentmove= chick_move_end_slash;
+ return true;
+ }
+ }
+ self.monsterinfo.currentmove= chick_move_end_slash;
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_slash[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 7, ChickSlash),
+ new mframe_t(ai_charge, -7, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, -2, chick_reslash)};
+ static mmove_t chick_move_slash=
+ new mmove_t(FRAME_attak204, FRAME_attak212, chick_frames_slash, null);
+
+ static mframe_t chick_frames_end_slash[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, -6, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -6, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t chick_move_end_slash=
+ new mmove_t(FRAME_attak213, FRAME_attak216, chick_frames_end_slash, chick_run);
+
+ static EntThinkAdapter chick_slash= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= chick_move_slash;
+ return true;
+ }
+ };
+
+ static mframe_t chick_frames_start_slash[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 8, null),
+ new mframe_t(ai_charge, 3, null)};
+ static mmove_t chick_move_start_slash=
+ new mmove_t(FRAME_attak201, FRAME_attak203, chick_frames_start_slash, chick_slash);
+
+ static EntThinkAdapter chick_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= chick_move_start_slash;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter chick_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= chick_move_start_attack1;
+ return true;
+ }
+ };
+
+ static EntInteractAdapter chick_sight= new EntInteractAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ /*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_chick(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_missile_prelaunch= gi.soundindex("chick/chkatck1.wav");
+ sound_missile_launch= gi.soundindex("chick/chkatck2.wav");
+ sound_melee_swing= gi.soundindex("chick/chkatck3.wav");
+ sound_melee_hit= gi.soundindex("chick/chkatck4.wav");
+ sound_missile_reload= gi.soundindex("chick/chkatck5.wav");
+ sound_death1= gi.soundindex("chick/chkdeth1.wav");
+ sound_death2= gi.soundindex("chick/chkdeth2.wav");
+ sound_fall_down= gi.soundindex("chick/chkfall1.wav");
+ sound_idle1= gi.soundindex("chick/chkidle1.wav");
+ sound_idle2= gi.soundindex("chick/chkidle2.wav");
+ sound_pain1= gi.soundindex("chick/chkpain1.wav");
+ sound_pain2= gi.soundindex("chick/chkpain2.wav");
+ sound_pain3= gi.soundindex("chick/chkpain3.wav");
+ sound_sight= gi.soundindex("chick/chksght1.wav");
+ sound_search= gi.soundindex("chick/chksrch1.wav");
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/bitch/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, 0);
+ Math3D.VectorSet(self.maxs, 16, 16, 56);
+
+ self.health= 175;
+ self.gib_health= -70;
+ self.mass= 200;
+
+ self.pain= chick_pain;
+ self.die= chick_die;
+
+ self.monsterinfo.stand= chick_stand;
+ self.monsterinfo.walk= chick_walk;
+ self.monsterinfo.run= chick_run;
+ self.monsterinfo.dodge= chick_dodge;
+ self.monsterinfo.attack= chick_attack;
+ self.monsterinfo.melee= chick_melee;
+ self.monsterinfo.sight= chick_sight;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove= chick_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Flash.java b/src/jake2/game/M_Flash.java
new file mode 100644
index 0000000..5ea18d1
--- /dev/null
+++ b/src/jake2/game/M_Flash.java
@@ -0,0 +1,707 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Flash.java,v 1.1 2004-07-07 19:59:12 hzi Exp $
+
+package jake2.game;
+
+public class M_Flash extends GameUtil
+{
+
+ // m_flash.c
+
+ // this file is included in both the game dll and quake2,
+ // the game needs it to source shot locations, the client
+ // needs it to position muzzle flashes
+ public static float monster_flash_offset[][]= {
+ // flash 0 is not used
+ { 0.0f, 0.0f, 0.0f },
+
+ // MZ2_TANK_BLASTER_1 1
+ {
+ 20.7f, -18.5f, 28.7f },
+ // MZ2_TANK_BLASTER_2 2
+ {
+ 16.6f, -21.5f, 30.1f },
+ // MZ2_TANK_BLASTER_3 3
+ {
+ 11.8f, -23.9f, 32.1f },
+ // MZ2_TANK_MACHINEGUN_1 4
+ {
+ 22.9f, -0.7f, 25.3f },
+ // MZ2_TANK_MACHINEGUN_2 5
+ {
+ 22.2f, 6.2f, 22.3f },
+ // MZ2_TANK_MACHINEGUN_3 6
+ {
+ 19.4f, 13.1f, 18.6f },
+ // MZ2_TANK_MACHINEGUN_4 7
+ {
+ 19.4f, 18.8f, 18.6f },
+ // MZ2_TANK_MACHINEGUN_5 8
+ {
+ 17.9f, 25.0f, 18.6f },
+ // MZ2_TANK_MACHINEGUN_6 9
+ {
+ 14.1f, 30.5f, 20.6f },
+ // MZ2_TANK_MACHINEGUN_7 10
+ {
+ 9.3f, 35.3f, 22.1f },
+ // MZ2_TANK_MACHINEGUN_8 11
+ {
+ 4.7f, 38.4f, 22.1f },
+ // MZ2_TANK_MACHINEGUN_9 12
+ {
+ -1.1f, 40.4f, 24.1f },
+ // MZ2_TANK_MACHINEGUN_10 13
+ {
+ -6.5f, 41.2f, 24.1f },
+ // MZ2_TANK_MACHINEGUN_11 14
+ {
+ 3.2f, 40.1f, 24.7f },
+ // MZ2_TANK_MACHINEGUN_12 15
+ {
+ 11.7f, 36.7f, 26.0f },
+ // MZ2_TANK_MACHINEGUN_13 16
+ {
+ 18.9f, 31.3f, 26.0f },
+ // MZ2_TANK_MACHINEGUN_14 17
+ {
+ 24.4f, 24.4f, 26.4f },
+ // MZ2_TANK_MACHINEGUN_15 18
+ {
+ 27.1f, 17.1f, 27.2f },
+ // MZ2_TANK_MACHINEGUN_16 19
+ {
+ 28.5f, 9.1f, 28.0f },
+ // MZ2_TANK_MACHINEGUN_17 20
+ {
+ 27.1f, 2.2f, 28.0f },
+ // MZ2_TANK_MACHINEGUN_18 21
+ {
+ 24.9f, -2.8f, 28.0f },
+ // MZ2_TANK_MACHINEGUN_19 22
+ {
+ 21.6f, -7.0f, 26.4f },
+ // MZ2_TANK_ROCKET_1 23
+ {
+ 6.2f, 29.1f, 49.1f },
+ // MZ2_TANK_ROCKET_2 24
+ {
+ 6.9f, 23.8f, 49.1f },
+ // MZ2_TANK_ROCKET_3 25
+ {
+ 8.3f, 17.8f, 49.5f },
+
+ // MZ2_INFANTRY_MACHINEGUN_1 26
+ {
+ 26.6f, 7.1f, 13.1f },
+ // MZ2_INFANTRY_MACHINEGUN_2 27
+ {
+ 18.2f, 7.5f, 15.4f },
+ // MZ2_INFANTRY_MACHINEGUN_3 28
+ {
+ 17.2f, 10.3f, 17.9f },
+ // MZ2_INFANTRY_MACHINEGUN_4 29
+ {
+ 17.0f, 12.8f, 20.1f },
+ // MZ2_INFANTRY_MACHINEGUN_5 30
+ {
+ 15.1f, 14.1f, 21.8f },
+ // MZ2_INFANTRY_MACHINEGUN_6 31
+ {
+ 11.8f, 17.2f, 23.1f },
+ // MZ2_INFANTRY_MACHINEGUN_7 32
+ {
+ 11.4f, 20.2f, 21.0f },
+ // MZ2_INFANTRY_MACHINEGUN_8 33
+ {
+ 9.0f, 23.0f, 18.9f },
+ // MZ2_INFANTRY_MACHINEGUN_9 34
+ {
+ 13.9f, 18.6f, 17.7f },
+ // MZ2_INFANTRY_MACHINEGUN_10 35
+ {
+ 15.4f, 15.6f, 15.8f },
+ // MZ2_INFANTRY_MACHINEGUN_11 36
+ {
+ 10.2f, 15.2f, 25.1f },
+ // MZ2_INFANTRY_MACHINEGUN_12 37
+ {
+ -1.9f, 15.1f, 28.2f },
+ // MZ2_INFANTRY_MACHINEGUN_13 38
+ {
+ -12.4f, 13.0f, 20.2f },
+
+ // MZ2_SOLDIER_BLASTER_1 39
+ {
+ 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f },
+ // MZ2_SOLDIER_BLASTER_2 40
+ {
+ 21.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_1 41
+ {
+ 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_2 42
+ {
+ 21.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_1 43
+ {
+ 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_2 44
+ {
+ 21.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f },
+
+ // MZ2_GUNNER_MACHINEGUN_1 45
+ {
+ 30.1f * 1.15f, 3.9f * 1.15f, 19.6f * 1.15f },
+ // MZ2_GUNNER_MACHINEGUN_2 46
+ {
+ 29.1f * 1.15f, 2.5f * 1.15f, 20.7f * 1.15f },
+ // MZ2_GUNNER_MACHINEGUN_3 47
+ {
+ 28.2f * 1.15f, 2.5f * 1.15f, 22.2f * 1.15f },
+ // MZ2_GUNNER_MACHINEGUN_4 48
+ {
+ 28.2f * 1.15f, 3.6f * 1.15f, 22.0f * 1.15f },
+ // MZ2_GUNNER_MACHINEGUN_5 49
+ {
+ 26.9f * 1.15f, 2.0f * 1.15f, 23.4f * 1.15f },
+ // MZ2_GUNNER_MACHINEGUN_6 50
+ {
+ 26.5f * 1.15f, 0.6f * 1.15f, 20.8f * 1.15f },
+ // MZ2_GUNNER_MACHINEGUN_7 51
+ {
+ 26.9f * 1.15f, 0.5f * 1.15f, 21.5f * 1.15f },
+ // MZ2_GUNNER_MACHINEGUN_8 52
+ {
+ 29.0f * 1.15f, 2.4f * 1.15f, 19.5f * 1.15f },
+ // MZ2_GUNNER_GRENADE_1 53
+ {
+ 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f },
+ // MZ2_GUNNER_GRENADE_2 54
+ {
+ 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f },
+ // MZ2_GUNNER_GRENADE_3 55
+ {
+ 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f },
+ // MZ2_GUNNER_GRENADE_4 56
+ {
+ 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f },
+
+ // MZ2_CHICK_ROCKET_1 57
+ // -24.8f, -9.0f, 39.0f},
+ {
+ 24.8f, -9.0f, 39.0f }, // PGM - this was incorrect in Q2
+
+ // MZ2_FLYER_BLASTER_1 58
+ {
+ 12.1f, 13.4f, -14.5f },
+ // MZ2_FLYER_BLASTER_2 59
+ {
+ 12.1f, -7.4f, -14.5f },
+
+ // MZ2_MEDIC_BLASTER_1 60
+ {
+ 12.1f, 5.4f, 16.5f },
+
+ // MZ2_GLADIATOR_RAILGUN_1 61
+ {
+ 30.0f, 18.0f, 28.0f },
+
+ // MZ2_HOVER_BLASTER_1 62
+ {
+ 32.5f, -0.8f, 10.0f },
+
+ // MZ2_ACTOR_MACHINEGUN_1 63
+ {
+ 18.4f, 7.4f, 9.6f },
+
+ // MZ2_SUPERTANK_MACHINEGUN_1 64
+ {
+ 30.0f, 30.0f, 88.5f },
+ // MZ2_SUPERTANK_MACHINEGUN_2 65
+ {
+ 30.0f, 30.0f, 88.5f },
+ // MZ2_SUPERTANK_MACHINEGUN_3 66
+ {
+ 30.0f, 30.0f, 88.5f },
+ // MZ2_SUPERTANK_MACHINEGUN_4 67
+ {
+ 30.0f, 30.0f, 88.5f },
+ // MZ2_SUPERTANK_MACHINEGUN_5 68
+ {
+ 30.0f, 30.0f, 88.5f },
+ // MZ2_SUPERTANK_MACHINEGUN_6 69
+ {
+ 30.0f, 30.0f, 88.5f },
+ // MZ2_SUPERTANK_ROCKET_1 70
+ {
+ 16.0f, -22.5f, 91.2f },
+ // MZ2_SUPERTANK_ROCKET_2 71
+ {
+ 16.0f, -33.4f, 86.7f },
+ // MZ2_SUPERTANK_ROCKET_3 72
+ {
+ 16.0f, -42.8f, 83.3f },
+
+ // --- Start Xian Stuff ---
+ // MZ2_BOSS2_MACHINEGUN_L1 73
+ {
+ 32f, -40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_L2 74
+ {
+ 32f, -40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_L3 75
+ {
+ 32f, -40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_L4 76
+ {
+ 32f, -40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_L5 77
+ {
+ 32f, -40f, 70f },
+ // --- End Xian Stuff
+
+ // MZ2_BOSS2_ROCKET_1 78
+ {
+ 22.0f, 16.0f, 10.0f },
+ // MZ2_BOSS2_ROCKET_2 79
+ {
+ 22.0f, 8.0f, 10.0f },
+ // MZ2_BOSS2_ROCKET_3 80
+ {
+ 22.0f, -8.0f, 10.0f },
+ // MZ2_BOSS2_ROCKET_4 81
+ {
+ 22.0f, -16.0f, 10.0f },
+
+ // MZ2_FLOAT_BLASTER_1 82
+ {
+ 32.5f, -0.8f, 10f },
+
+ // MZ2_SOLDIER_BLASTER_3 83
+ {
+ 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_3 84
+ {
+ 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_3 85
+ {
+ 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f },
+ // MZ2_SOLDIER_BLASTER_4 86
+ {
+ 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_4 87
+ {
+ 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_4 88
+ {
+ 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f },
+ // MZ2_SOLDIER_BLASTER_5 89
+ {
+ 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_5 90
+ {
+ 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_5 91
+ {
+ 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f },
+ // MZ2_SOLDIER_BLASTER_6 92
+ {
+ 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_6 93
+ {
+ 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_6 94
+ {
+ 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f },
+ // MZ2_SOLDIER_BLASTER_7 95
+ {
+ 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_7 96
+ {
+ 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_7 97
+ {
+ 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f },
+ // MZ2_SOLDIER_BLASTER_8 98
+ // 34.5f * 1.2f, 9.6f * 1.2f, 6.1f * 1.2f},
+ {
+ 31.5f * 1.2f, 9.6f * 1.2f, 10.1f * 1.2f },
+ // MZ2_SOLDIER_SHOTGUN_8 99
+ {
+ 34.5f * 1.2f, 9.6f * 1.2f, 6.1f * 1.2f },
+ // MZ2_SOLDIER_MACHINEGUN_8 100
+ {
+ 34.5f * 1.2f, 9.6f * 1.2f, 6.1f * 1.2f },
+
+ // --- Xian shit below ---
+ // MZ2_MAKRON_BFG 101
+ {
+ 17f, -19.5f, 62.9f },
+ // MZ2_MAKRON_BLASTER_1 102
+ {
+ -3.6f, -24.1f, 59.5f },
+ // MZ2_MAKRON_BLASTER_2 103
+ {
+ -1.6f, -19.3f, 59.5f },
+ // MZ2_MAKRON_BLASTER_3 104
+ {
+ -0.1f, -14.4f, 59.5f },
+ // MZ2_MAKRON_BLASTER_4 105
+ {
+ 2.0f, -7.6f, 59.5f },
+ // MZ2_MAKRON_BLASTER_5 106
+ {
+ 3.4f, 1.3f, 59.5f },
+ // MZ2_MAKRON_BLASTER_6 107
+ {
+ 3.7f, 11.1f, 59.5f },
+ // MZ2_MAKRON_BLASTER_7 108
+ {
+ -0.3f, 22.3f, 59.5f },
+ // MZ2_MAKRON_BLASTER_8 109
+ {
+ -6f, 33f, 59.5f },
+ // MZ2_MAKRON_BLASTER_9 110
+ {
+ -9.3f, 36.4f, 59.5f },
+ // MZ2_MAKRON_BLASTER_10 111
+ {
+ -7f, 35f, 59.5f },
+ // MZ2_MAKRON_BLASTER_11 112
+ {
+ -2.1f, 29f, 59.5f },
+ // MZ2_MAKRON_BLASTER_12 113
+ {
+ 3.9f, 17.3f, 59.5f },
+ // MZ2_MAKRON_BLASTER_13 114
+ {
+ 6.1f, 5.8f, 59.5f },
+ // MZ2_MAKRON_BLASTER_14 115
+ {
+ 5.9f, -4.4f, 59.5f },
+ // MZ2_MAKRON_BLASTER_15 116
+ {
+ 4.2f, -14.1f, 59.5f },
+ // MZ2_MAKRON_BLASTER_16 117
+ {
+ 2.4f, -18.8f, 59.5f },
+ // MZ2_MAKRON_BLASTER_17 118
+ {
+ -1.8f, -25.5f, 59.5f },
+ // MZ2_MAKRON_RAILGUN_1 119
+ {
+ -17.3f, 7.8f, 72.4f },
+
+ // MZ2_JORG_MACHINEGUN_L1 120
+ {
+ 78.5f, -47.1f, 96f },
+ // MZ2_JORG_MACHINEGUN_L2 121
+ {
+ 78.5f, -47.1f, 96f },
+ // MZ2_JORG_MACHINEGUN_L3 122
+ {
+ 78.5f, -47.1f, 96f },
+ // MZ2_JORG_MACHINEGUN_L4 123
+ {
+ 78.5f, -47.1f, 96f },
+ // MZ2_JORG_MACHINEGUN_L5 124
+ {
+ 78.5f, -47.1f, 96f },
+ // MZ2_JORG_MACHINEGUN_L6 125
+ {
+ 78.5f, -47.1f, 96f },
+ // MZ2_JORG_MACHINEGUN_R1 126
+ {
+ 78.5f, 46.7f, 96f },
+ // MZ2_JORG_MACHINEGUN_R2 127
+ {
+ 78.5f, 46.7f, 96f },
+ // MZ2_JORG_MACHINEGUN_R3 128
+ {
+ 78.5f, 46.7f, 96f },
+ // MZ2_JORG_MACHINEGUN_R4 129
+ {
+ 78.5f, 46.7f, 96f },
+ // MZ2_JORG_MACHINEGUN_R5 130
+ {
+ 78.5f, 46.7f, 96f },
+ // MZ2_JORG_MACHINEGUN_R6 131
+ {
+ 78.5f, 46.7f, 96f },
+ // MZ2_JORG_BFG_1 132
+ {
+ 6.3f, -9f, 111.2f },
+
+ // MZ2_BOSS2_MACHINEGUN_R1 73
+ {
+ 32f, 40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_R2 74
+ {
+ 32f, 40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_R3 75
+ {
+ 32f, 40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_R4 76
+ {
+ 32f, 40f, 70f },
+ // MZ2_BOSS2_MACHINEGUN_R5 77
+ {
+ 32f, 40f, 70f },
+
+ // --- End Xian Shit ---
+
+ // ROGUE
+ // note that the above really ends at 137
+ // carrier machineguns
+ // MZ2_CARRIER_MACHINEGUN_L1
+ {
+ 56f, -32f, 32f },
+ // MZ2_CARRIER_MACHINEGUN_R1
+ {
+ 56f, 32f, 32f },
+ // MZ2_CARRIER_GRENADE
+ {
+ 42f, 24f, 50f },
+ // MZ2_TURRET_MACHINEGUN 141
+ {
+ 16f, 0f, 0f },
+ // MZ2_TURRET_ROCKET 142
+ {
+ 16f, 0f, 0f },
+ // MZ2_TURRET_BLASTER 143
+ {
+ 16f, 0f, 0f },
+ // MZ2_STALKER_BLASTER 144
+ {
+ 24f, 0f, 6f },
+ // MZ2_DAEDALUS_BLASTER 145
+ {
+ 32.5f, -0.8f, 10.0f },
+ // MZ2_MEDIC_BLASTER_2 146
+ {
+ 12.1f, 5.4f, 16.5f },
+ // MZ2_CARRIER_RAILGUN 147
+ {
+ 32f, 0f, 6f },
+ // MZ2_WIDOW_DISRUPTOR 148
+ {
+ 57.72f, 14.50f, 88.81f },
+ // MZ2_WIDOW_BLASTER 149
+ {
+ 56f, 32f, 32f },
+ // MZ2_WIDOW_RAIL 150
+ {
+ 62f, -20f, 84f },
+ // MZ2_WIDOW_PLASMABEAM 151 // PMM - not used!
+ {
+ 32f, 0f, 6f },
+ // MZ2_CARRIER_MACHINEGUN_L2 152
+ {
+ 61f, -32f, 12f },
+ // MZ2_CARRIER_MACHINEGUN_R2 153
+ {
+ 61f, 32f, 12f },
+ // MZ2_WIDOW_RAIL_LEFT 154
+ {
+ 17f, -62f, 91f },
+ // MZ2_WIDOW_RAIL_RIGHT 155
+ {
+ 68f, 12f, 86f },
+ // MZ2_WIDOW_BLASTER_SWEEP1 156 pmm - the sweeps need to be in sequential order
+ {
+ 47.5f, 56f, 89f },
+ // MZ2_WIDOW_BLASTER_SWEEP2 157
+ {
+ 54f, 52f, 91f },
+ // MZ2_WIDOW_BLASTER_SWEEP3 158
+ {
+ 58f, 40f, 91f },
+ // MZ2_WIDOW_BLASTER_SWEEP4 159
+ {
+ 68f, 30f, 88f },
+ // MZ2_WIDOW_BLASTER_SWEEP5 160
+ {
+ 74f, 20f, 88f },
+ // MZ2_WIDOW_BLASTER_SWEEP6 161
+ {
+ 73f, 11f, 87f },
+ // MZ2_WIDOW_BLASTER_SWEEP7 162
+ {
+ 73f, 3f, 87f },
+ // MZ2_WIDOW_BLASTER_SWEEP8 163
+ {
+ 70f, -12f, 87f },
+ // MZ2_WIDOW_BLASTER_SWEEP9 164
+ {
+ 67f, -20f, 90f },
+ // MZ2_WIDOW_BLASTER_100 165
+ {
+ -20f, 76f, 90f },
+ // MZ2_WIDOW_BLASTER_90 166
+ {
+ -8f, 74f, 90f },
+ // MZ2_WIDOW_BLASTER_80 167
+ {
+ 0f, 72f, 90f },
+ // MZ2_WIDOW_BLASTER_70 168 d06
+ {
+ 10f, 71f, 89f },
+ // MZ2_WIDOW_BLASTER_60 169 d07
+ {
+ 23f, 70f, 87f },
+ // MZ2_WIDOW_BLASTER_50 170 d08
+ {
+ 32f, 64f, 85f },
+ // MZ2_WIDOW_BLASTER_40 171
+ {
+ 40f, 58f, 84f },
+ // MZ2_WIDOW_BLASTER_30 172 d10
+ {
+ 48f, 50f, 83f },
+ // MZ2_WIDOW_BLASTER_20 173
+ {
+ 54f, 42f, 82f },
+ // MZ2_WIDOW_BLASTER_10 174 d12
+ {
+ 56f, 34f, 82f },
+ // MZ2_WIDOW_BLASTER_0 175
+ {
+ 58f, 26f, 82f },
+ // MZ2_WIDOW_BLASTER_10L 176 d14
+ {
+ 60f, 16f, 82f },
+ // MZ2_WIDOW_BLASTER_20L 177
+ {
+ 59f, 6f, 81f },
+ // MZ2_WIDOW_BLASTER_30L 178 d16
+ {
+ 58f, -2f, 80f },
+ // MZ2_WIDOW_BLASTER_40L 179
+ {
+ 57f, -10f, 79f },
+ // MZ2_WIDOW_BLASTER_50L 180 d18
+ {
+ 54f, -18f, 78f },
+ // MZ2_WIDOW_BLASTER_60L 181
+ {
+ 42f, -32f, 80f },
+ // MZ2_WIDOW_BLASTER_70L 182 d20
+ {
+ 36f, -40f, 78f },
+ // MZ2_WIDOW_RUN_1 183
+ {
+ 68.4f, 10.88f, 82.08f },
+ // MZ2_WIDOW_RUN_2 184
+ {
+ 68.51f, 8.64f, 85.14f },
+ // MZ2_WIDOW_RUN_3 185
+ {
+ 68.66f, 6.38f, 88.78f },
+ // MZ2_WIDOW_RUN_4 186
+ {
+ 68.73f, 5.1f, 84.47f },
+ // MZ2_WIDOW_RUN_5 187
+ {
+ 68.82f, 4.79f, 80.52f },
+ // MZ2_WIDOW_RUN_6 188
+ {
+ 68.77f, 6.11f, 85.37f },
+ // MZ2_WIDOW_RUN_7 189
+ {
+ 68.67f, 7.99f, 90.24f },
+ // MZ2_WIDOW_RUN_8 190
+ {
+ 68.55f, 9.54f, 87.36f },
+ // MZ2_CARRIER_ROCKET_1 191
+ {
+ 0f, 0f, -5f },
+ // MZ2_CARRIER_ROCKET_2 192
+ {
+ 0f, 0f, -5f },
+ // MZ2_CARRIER_ROCKET_3 193
+ {
+ 0f, 0f, -5f },
+ // MZ2_CARRIER_ROCKET_4 194
+ {
+ 0f, 0f, -5f },
+ // MZ2_WIDOW2_BEAMER_1 195
+ // 72.13f, -17.63f, 93.77f},
+ {
+ 69.00f, -17.63f, 93.77f },
+ // MZ2_WIDOW2_BEAMER_2 196
+ // 71.46f, -17.08f, 89.82f},
+ {
+ 69.00f, -17.08f, 89.82f },
+ // MZ2_WIDOW2_BEAMER_3 197
+ // 71.47f, -18.40f, 90.70f},
+ {
+ 69.00f, -18.40f, 90.70f },
+ // MZ2_WIDOW2_BEAMER_4 198
+ // 71.96f, -18.34f, 94.32f},
+ {
+ 69.00f, -18.34f, 94.32f },
+ // MZ2_WIDOW2_BEAMER_5 199
+ // 72.25f, -18.30f, 97.98f},
+ {
+ 69.00f, -18.30f, 97.98f },
+ // MZ2_WIDOW2_BEAM_SWEEP_1 200
+ {
+ 45.04f, -59.02f, 92.24f },
+ // MZ2_WIDOW2_BEAM_SWEEP_2 201
+ {
+ 50.68f, -54.70f, 91.96f },
+ // MZ2_WIDOW2_BEAM_SWEEP_3 202
+ {
+ 56.57f, -47.72f, 91.65f },
+ // MZ2_WIDOW2_BEAM_SWEEP_4 203
+ {
+ 61.75f, -38.75f, 91.38f },
+ // MZ2_WIDOW2_BEAM_SWEEP_5 204
+ {
+ 65.55f, -28.76f, 91.24f },
+ // MZ2_WIDOW2_BEAM_SWEEP_6 205
+ {
+ 67.79f, -18.90f, 91.22f },
+ // MZ2_WIDOW2_BEAM_SWEEP_7 206
+ {
+ 68.60f, -9.52f, 91.23f },
+ // MZ2_WIDOW2_BEAM_SWEEP_8 207
+ {
+ 68.08f, 0.18f, 91.32f },
+ // MZ2_WIDOW2_BEAM_SWEEP_9 208
+ {
+ 66.14f, 9.79f, 91.44f },
+ // MZ2_WIDOW2_BEAM_SWEEP_10 209
+ {
+ 62.77f, 18.91f, 91.65f },
+ // MZ2_WIDOW2_BEAM_SWEEP_11 210
+ {
+ 58.29f, 27.11f, 92.00f },
+
+ // end of table
+ {
+ 0.0f, 0.0f, 0.0f }
+ };
+
+}
diff --git a/src/jake2/game/M_Flipper.java b/src/jake2/game/M_Flipper.java
new file mode 100644
index 0000000..a1e019d
--- /dev/null
+++ b/src/jake2/game/M_Flipper.java
@@ -0,0 +1,627 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Flipper.java,v 1.1 2004-07-07 19:59:12 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Flipper extends Game {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_flpbit01= 0;
+ public final static int FRAME_flpbit02= 1;
+ public final static int FRAME_flpbit03= 2;
+ public final static int FRAME_flpbit04= 3;
+ public final static int FRAME_flpbit05= 4;
+ public final static int FRAME_flpbit06= 5;
+ public final static int FRAME_flpbit07= 6;
+ public final static int FRAME_flpbit08= 7;
+ public final static int FRAME_flpbit09= 8;
+ public final static int FRAME_flpbit10= 9;
+ public final static int FRAME_flpbit11= 10;
+ public final static int FRAME_flpbit12= 11;
+ public final static int FRAME_flpbit13= 12;
+ public final static int FRAME_flpbit14= 13;
+ public final static int FRAME_flpbit15= 14;
+ public final static int FRAME_flpbit16= 15;
+ public final static int FRAME_flpbit17= 16;
+ public final static int FRAME_flpbit18= 17;
+ public final static int FRAME_flpbit19= 18;
+ public final static int FRAME_flpbit20= 19;
+ public final static int FRAME_flptal01= 20;
+ public final static int FRAME_flptal02= 21;
+ public final static int FRAME_flptal03= 22;
+ public final static int FRAME_flptal04= 23;
+ public final static int FRAME_flptal05= 24;
+ public final static int FRAME_flptal06= 25;
+ public final static int FRAME_flptal07= 26;
+ public final static int FRAME_flptal08= 27;
+ public final static int FRAME_flptal09= 28;
+ public final static int FRAME_flptal10= 29;
+ public final static int FRAME_flptal11= 30;
+ public final static int FRAME_flptal12= 31;
+ public final static int FRAME_flptal13= 32;
+ public final static int FRAME_flptal14= 33;
+ public final static int FRAME_flptal15= 34;
+ public final static int FRAME_flptal16= 35;
+ public final static int FRAME_flptal17= 36;
+ public final static int FRAME_flptal18= 37;
+ public final static int FRAME_flptal19= 38;
+ public final static int FRAME_flptal20= 39;
+ public final static int FRAME_flptal21= 40;
+ public final static int FRAME_flphor01= 41;
+ public final static int FRAME_flphor02= 42;
+ public final static int FRAME_flphor03= 43;
+ public final static int FRAME_flphor04= 44;
+ public final static int FRAME_flphor05= 45;
+ public final static int FRAME_flphor06= 46;
+ public final static int FRAME_flphor07= 47;
+ public final static int FRAME_flphor08= 48;
+ public final static int FRAME_flphor09= 49;
+ public final static int FRAME_flphor10= 50;
+ public final static int FRAME_flphor11= 51;
+ public final static int FRAME_flphor12= 52;
+ public final static int FRAME_flphor13= 53;
+ public final static int FRAME_flphor14= 54;
+ public final static int FRAME_flphor15= 55;
+ public final static int FRAME_flphor16= 56;
+ public final static int FRAME_flphor17= 57;
+ public final static int FRAME_flphor18= 58;
+ public final static int FRAME_flphor19= 59;
+ public final static int FRAME_flphor20= 60;
+ public final static int FRAME_flphor21= 61;
+ public final static int FRAME_flphor22= 62;
+ public final static int FRAME_flphor23= 63;
+ public final static int FRAME_flphor24= 64;
+ public final static int FRAME_flpver01= 65;
+ public final static int FRAME_flpver02= 66;
+ public final static int FRAME_flpver03= 67;
+ public final static int FRAME_flpver04= 68;
+ public final static int FRAME_flpver05= 69;
+ public final static int FRAME_flpver06= 70;
+ public final static int FRAME_flpver07= 71;
+ public final static int FRAME_flpver08= 72;
+ public final static int FRAME_flpver09= 73;
+ public final static int FRAME_flpver10= 74;
+ public final static int FRAME_flpver11= 75;
+ public final static int FRAME_flpver12= 76;
+ public final static int FRAME_flpver13= 77;
+ public final static int FRAME_flpver14= 78;
+ public final static int FRAME_flpver15= 79;
+ public final static int FRAME_flpver16= 80;
+ public final static int FRAME_flpver17= 81;
+ public final static int FRAME_flpver18= 82;
+ public final static int FRAME_flpver19= 83;
+ public final static int FRAME_flpver20= 84;
+ public final static int FRAME_flpver21= 85;
+ public final static int FRAME_flpver22= 86;
+ public final static int FRAME_flpver23= 87;
+ public final static int FRAME_flpver24= 88;
+ public final static int FRAME_flpver25= 89;
+ public final static int FRAME_flpver26= 90;
+ public final static int FRAME_flpver27= 91;
+ public final static int FRAME_flpver28= 92;
+ public final static int FRAME_flpver29= 93;
+ public final static int FRAME_flppn101= 94;
+ public final static int FRAME_flppn102= 95;
+ public final static int FRAME_flppn103= 96;
+ public final static int FRAME_flppn104= 97;
+ public final static int FRAME_flppn105= 98;
+ public final static int FRAME_flppn201= 99;
+ public final static int FRAME_flppn202= 100;
+ public final static int FRAME_flppn203= 101;
+ public final static int FRAME_flppn204= 102;
+ public final static int FRAME_flppn205= 103;
+ public final static int FRAME_flpdth01= 104;
+ public final static int FRAME_flpdth02= 105;
+ public final static int FRAME_flpdth03= 106;
+ public final static int FRAME_flpdth04= 107;
+ public final static int FRAME_flpdth05= 108;
+ public final static int FRAME_flpdth06= 109;
+ public final static int FRAME_flpdth07= 110;
+ public final static int FRAME_flpdth08= 111;
+ public final static int FRAME_flpdth09= 112;
+ public final static int FRAME_flpdth10= 113;
+ public final static int FRAME_flpdth11= 114;
+ public final static int FRAME_flpdth12= 115;
+ public final static int FRAME_flpdth13= 116;
+ public final static int FRAME_flpdth14= 117;
+ public final static int FRAME_flpdth15= 118;
+ public final static int FRAME_flpdth16= 119;
+ public final static int FRAME_flpdth17= 120;
+ public final static int FRAME_flpdth18= 121;
+ public final static int FRAME_flpdth19= 122;
+ public final static int FRAME_flpdth20= 123;
+ public final static int FRAME_flpdth21= 124;
+ public final static int FRAME_flpdth22= 125;
+ public final static int FRAME_flpdth23= 126;
+ public final static int FRAME_flpdth24= 127;
+ public final static int FRAME_flpdth25= 128;
+ public final static int FRAME_flpdth26= 129;
+ public final static int FRAME_flpdth27= 130;
+ public final static int FRAME_flpdth28= 131;
+ public final static int FRAME_flpdth29= 132;
+ public final static int FRAME_flpdth30= 133;
+ public final static int FRAME_flpdth31= 134;
+ public final static int FRAME_flpdth32= 135;
+ public final static int FRAME_flpdth33= 136;
+ public final static int FRAME_flpdth34= 137;
+ public final static int FRAME_flpdth35= 138;
+ public final static int FRAME_flpdth36= 139;
+ public final static int FRAME_flpdth37= 140;
+ public final static int FRAME_flpdth38= 141;
+ public final static int FRAME_flpdth39= 142;
+ public final static int FRAME_flpdth40= 143;
+ public final static int FRAME_flpdth41= 144;
+ public final static int FRAME_flpdth42= 145;
+ public final static int FRAME_flpdth43= 146;
+ public final static int FRAME_flpdth44= 147;
+ public final static int FRAME_flpdth45= 148;
+ public final static int FRAME_flpdth46= 149;
+ public final static int FRAME_flpdth47= 150;
+ public final static int FRAME_flpdth48= 151;
+ public final static int FRAME_flpdth49= 152;
+ public final static int FRAME_flpdth50= 153;
+ public final static int FRAME_flpdth51= 154;
+ public final static int FRAME_flpdth52= 155;
+ public final static int FRAME_flpdth53= 156;
+ public final static int FRAME_flpdth54= 157;
+ public final static int FRAME_flpdth55= 158;
+ public final static int FRAME_flpdth56= 159;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_chomp;
+ static int sound_attack;
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_death;
+ static int sound_idle;
+ static int sound_search;
+ static int sound_sight;
+
+ static mframe_t flipper_frames_stand[]=
+ new mframe_t[] { new mframe_t(ai_stand, 0, null)};
+
+ static mmove_t flipper_move_stand=
+ new mmove_t(FRAME_flphor01, FRAME_flphor01, flipper_frames_stand, null);
+
+ static EntThinkAdapter flipper_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flipper_move_stand;
+ return true;
+ }
+ };
+
+ public final static int FLIPPER_RUN_SPEED= 24;
+
+ static mframe_t flipper_frames_run[]=
+ new mframe_t[] { new mframe_t(ai_run, FLIPPER_RUN_SPEED, null), // 6
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ // 10
+
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ // 20
+
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null),
+ new mframe_t(ai_run, FLIPPER_RUN_SPEED, null) // 29
+ };
+ static mmove_t flipper_move_run_loop=
+ new mmove_t(FRAME_flpver06, FRAME_flpver29, flipper_frames_run, null);
+
+ static EntThinkAdapter flipper_run_loop= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flipper_move_run_loop;
+ return true;
+ }
+ };
+
+ static mframe_t flipper_frames_run_start[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null)};
+ static mmove_t flipper_move_run_start=
+ new mmove_t(
+ FRAME_flpver01,
+ FRAME_flpver06,
+ flipper_frames_run_start,
+ flipper_run_loop);
+
+ static EntThinkAdapter flipper_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flipper_move_run_start;
+ return true;
+ }
+ };
+
+ /* Standard Swimming */
+ static mframe_t flipper_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null)};
+ static mmove_t flipper_move_walk=
+ new mmove_t(FRAME_flphor01, FRAME_flphor24, flipper_frames_walk, null);
+
+ static EntThinkAdapter flipper_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flipper_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t flipper_frames_start_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 8, flipper_run)};
+ static mmove_t flipper_move_start_run=
+ new mmove_t(
+ FRAME_flphor01,
+ FRAME_flphor05,
+ flipper_frames_start_run,
+ null);
+
+ static EntThinkAdapter flipper_start_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flipper_move_start_run;
+ return true;
+ }
+ };
+
+ static mframe_t flipper_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flipper_move_pain2=
+ new mmove_t(
+ FRAME_flppn101,
+ FRAME_flppn105,
+ flipper_frames_pain2,
+ flipper_run);
+
+ static mframe_t flipper_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flipper_move_pain1=
+ new mmove_t(
+ FRAME_flppn201,
+ FRAME_flppn205,
+ flipper_frames_pain1,
+ flipper_run);
+ static EntThinkAdapter flipper_bite= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim= { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, 0, 0);
+ Fire.fire_hit(self, aim, 5, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flipper_preattack= new EntThinkAdapter() {
+
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_chomp, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t flipper_frames_attack[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, flipper_preattack),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, flipper_bite),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, flipper_bite),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t flipper_move_attack=
+ new mmove_t(
+ FRAME_flpbit01,
+ FRAME_flpbit20,
+ flipper_frames_attack,
+ flipper_run);
+
+ static EntThinkAdapter flipper_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flipper_move_attack;
+ return true;
+ }
+ };
+
+ static EntPainAdapter flipper_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ int n;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ n= (Lib.rand() + 1) % 2;
+ if (n == 0) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= flipper_move_pain1;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= flipper_move_pain2;
+ }
+ return;
+ }
+ };
+
+ static EntThinkAdapter flipper_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t flipper_frames_death[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flipper_move_death=
+ new mmove_t(
+ FRAME_flpdth01,
+ FRAME_flpdth56,
+ flipper_frames_death,
+ flipper_dead);
+
+ static EntInteractAdapter flipper_sight= new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntDieAdapter flipper_die= new EntDieAdapter() {
+
+ public void flipper_die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(
+ self,
+ CHAN_VOICE,
+ gi.soundindex("misc/udeath.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ for (n= 0; n < 2; n++)
+ ThrowGib(
+ self,
+ "models/objects/gibs/bone/tris.md2",
+ damage,
+ GIB_ORGANIC);
+ for (n= 0; n < 2; n++)
+ ThrowGib(
+ self,
+ "models/objects/gibs/sm_meat/tris.md2",
+ damage,
+ GIB_ORGANIC);
+ ThrowHead(
+ self,
+ "models/objects/gibs/sm_meat/tris.md2",
+ damage,
+ GIB_ORGANIC);
+ self.deadflag= DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_YES;
+ self.monsterinfo.currentmove= flipper_move_death;
+ }
+ };
+
+ /*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ public static void SP_monster_flipper(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_pain1= gi.soundindex("flipper/flppain1.wav");
+ sound_pain2= gi.soundindex("flipper/flppain2.wav");
+ sound_death= gi.soundindex("flipper/flpdeth1.wav");
+ sound_chomp= gi.soundindex("flipper/flpatck1.wav");
+ sound_attack= gi.soundindex("flipper/flpatck2.wav");
+ sound_idle= gi.soundindex("flipper/flpidle1.wav");
+ sound_search= gi.soundindex("flipper/flpsrch1.wav");
+ sound_sight= gi.soundindex("flipper/flpsght1.wav");
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/flipper/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, 0);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+
+ self.health= 50;
+ self.gib_health= -30;
+ self.mass= 100;
+
+ self.pain= flipper_pain;
+ self.die= flipper_die;
+
+ self.monsterinfo.stand= flipper_stand;
+ self.monsterinfo.walk= flipper_walk;
+ self.monsterinfo.run= flipper_start_run;
+ self.monsterinfo.melee= flipper_melee;
+ self.monsterinfo.sight= flipper_sight;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove= flipper_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ swimmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Float.java b/src/jake2/game/M_Float.java
new file mode 100644
index 0000000..0640105
--- /dev/null
+++ b/src/jake2/game/M_Float.java
@@ -0,0 +1,1007 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Float.java,v 1.1 2004-07-07 19:59:13 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Float extends Game {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_actvat01= 0;
+ public final static int FRAME_actvat02= 1;
+ public final static int FRAME_actvat03= 2;
+ public final static int FRAME_actvat04= 3;
+ public final static int FRAME_actvat05= 4;
+ public final static int FRAME_actvat06= 5;
+ public final static int FRAME_actvat07= 6;
+ public final static int FRAME_actvat08= 7;
+ public final static int FRAME_actvat09= 8;
+ public final static int FRAME_actvat10= 9;
+ public final static int FRAME_actvat11= 10;
+ public final static int FRAME_actvat12= 11;
+ public final static int FRAME_actvat13= 12;
+ public final static int FRAME_actvat14= 13;
+ public final static int FRAME_actvat15= 14;
+ public final static int FRAME_actvat16= 15;
+ public final static int FRAME_actvat17= 16;
+ public final static int FRAME_actvat18= 17;
+ public final static int FRAME_actvat19= 18;
+ public final static int FRAME_actvat20= 19;
+ public final static int FRAME_actvat21= 20;
+ public final static int FRAME_actvat22= 21;
+ public final static int FRAME_actvat23= 22;
+ public final static int FRAME_actvat24= 23;
+ public final static int FRAME_actvat25= 24;
+ public final static int FRAME_actvat26= 25;
+ public final static int FRAME_actvat27= 26;
+ public final static int FRAME_actvat28= 27;
+ public final static int FRAME_actvat29= 28;
+ public final static int FRAME_actvat30= 29;
+ public final static int FRAME_actvat31= 30;
+ public final static int FRAME_attak101= 31;
+ public final static int FRAME_attak102= 32;
+ public final static int FRAME_attak103= 33;
+ public final static int FRAME_attak104= 34;
+ public final static int FRAME_attak105= 35;
+ public final static int FRAME_attak106= 36;
+ public final static int FRAME_attak107= 37;
+ public final static int FRAME_attak108= 38;
+ public final static int FRAME_attak109= 39;
+ public final static int FRAME_attak110= 40;
+ public final static int FRAME_attak111= 41;
+ public final static int FRAME_attak112= 42;
+ public final static int FRAME_attak113= 43;
+ public final static int FRAME_attak114= 44;
+ public final static int FRAME_attak201= 45;
+ public final static int FRAME_attak202= 46;
+ public final static int FRAME_attak203= 47;
+ public final static int FRAME_attak204= 48;
+ public final static int FRAME_attak205= 49;
+ public final static int FRAME_attak206= 50;
+ public final static int FRAME_attak207= 51;
+ public final static int FRAME_attak208= 52;
+ public final static int FRAME_attak209= 53;
+ public final static int FRAME_attak210= 54;
+ public final static int FRAME_attak211= 55;
+ public final static int FRAME_attak212= 56;
+ public final static int FRAME_attak213= 57;
+ public final static int FRAME_attak214= 58;
+ public final static int FRAME_attak215= 59;
+ public final static int FRAME_attak216= 60;
+ public final static int FRAME_attak217= 61;
+ public final static int FRAME_attak218= 62;
+ public final static int FRAME_attak219= 63;
+ public final static int FRAME_attak220= 64;
+ public final static int FRAME_attak221= 65;
+ public final static int FRAME_attak222= 66;
+ public final static int FRAME_attak223= 67;
+ public final static int FRAME_attak224= 68;
+ public final static int FRAME_attak225= 69;
+ public final static int FRAME_attak301= 70;
+ public final static int FRAME_attak302= 71;
+ public final static int FRAME_attak303= 72;
+ public final static int FRAME_attak304= 73;
+ public final static int FRAME_attak305= 74;
+ public final static int FRAME_attak306= 75;
+ public final static int FRAME_attak307= 76;
+ public final static int FRAME_attak308= 77;
+ public final static int FRAME_attak309= 78;
+ public final static int FRAME_attak310= 79;
+ public final static int FRAME_attak311= 80;
+ public final static int FRAME_attak312= 81;
+ public final static int FRAME_attak313= 82;
+ public final static int FRAME_attak314= 83;
+ public final static int FRAME_attak315= 84;
+ public final static int FRAME_attak316= 85;
+ public final static int FRAME_attak317= 86;
+ public final static int FRAME_attak318= 87;
+ public final static int FRAME_attak319= 88;
+ public final static int FRAME_attak320= 89;
+ public final static int FRAME_attak321= 90;
+ public final static int FRAME_attak322= 91;
+ public final static int FRAME_attak323= 92;
+ public final static int FRAME_attak324= 93;
+ public final static int FRAME_attak325= 94;
+ public final static int FRAME_attak326= 95;
+ public final static int FRAME_attak327= 96;
+ public final static int FRAME_attak328= 97;
+ public final static int FRAME_attak329= 98;
+ public final static int FRAME_attak330= 99;
+ public final static int FRAME_attak331= 100;
+ public final static int FRAME_attak332= 101;
+ public final static int FRAME_attak333= 102;
+ public final static int FRAME_attak334= 103;
+ public final static int FRAME_death01= 104;
+ public final static int FRAME_death02= 105;
+ public final static int FRAME_death03= 106;
+ public final static int FRAME_death04= 107;
+ public final static int FRAME_death05= 108;
+ public final static int FRAME_death06= 109;
+ public final static int FRAME_death07= 110;
+ public final static int FRAME_death08= 111;
+ public final static int FRAME_death09= 112;
+ public final static int FRAME_death10= 113;
+ public final static int FRAME_death11= 114;
+ public final static int FRAME_death12= 115;
+ public final static int FRAME_death13= 116;
+ public final static int FRAME_pain101= 117;
+ public final static int FRAME_pain102= 118;
+ public final static int FRAME_pain103= 119;
+ public final static int FRAME_pain104= 120;
+ public final static int FRAME_pain105= 121;
+ public final static int FRAME_pain106= 122;
+ public final static int FRAME_pain107= 123;
+ public final static int FRAME_pain201= 124;
+ public final static int FRAME_pain202= 125;
+ public final static int FRAME_pain203= 126;
+ public final static int FRAME_pain204= 127;
+ public final static int FRAME_pain205= 128;
+ public final static int FRAME_pain206= 129;
+ public final static int FRAME_pain207= 130;
+ public final static int FRAME_pain208= 131;
+ public final static int FRAME_pain301= 132;
+ public final static int FRAME_pain302= 133;
+ public final static int FRAME_pain303= 134;
+ public final static int FRAME_pain304= 135;
+ public final static int FRAME_pain305= 136;
+ public final static int FRAME_pain306= 137;
+ public final static int FRAME_pain307= 138;
+ public final static int FRAME_pain308= 139;
+ public final static int FRAME_pain309= 140;
+ public final static int FRAME_pain310= 141;
+ public final static int FRAME_pain311= 142;
+ public final static int FRAME_pain312= 143;
+ public final static int FRAME_stand101= 144;
+ public final static int FRAME_stand102= 145;
+ public final static int FRAME_stand103= 146;
+ public final static int FRAME_stand104= 147;
+ public final static int FRAME_stand105= 148;
+ public final static int FRAME_stand106= 149;
+ public final static int FRAME_stand107= 150;
+ public final static int FRAME_stand108= 151;
+ public final static int FRAME_stand109= 152;
+ public final static int FRAME_stand110= 153;
+ public final static int FRAME_stand111= 154;
+ public final static int FRAME_stand112= 155;
+ public final static int FRAME_stand113= 156;
+ public final static int FRAME_stand114= 157;
+ public final static int FRAME_stand115= 158;
+ public final static int FRAME_stand116= 159;
+ public final static int FRAME_stand117= 160;
+ public final static int FRAME_stand118= 161;
+ public final static int FRAME_stand119= 162;
+ public final static int FRAME_stand120= 163;
+ public final static int FRAME_stand121= 164;
+ public final static int FRAME_stand122= 165;
+ public final static int FRAME_stand123= 166;
+ public final static int FRAME_stand124= 167;
+ public final static int FRAME_stand125= 168;
+ public final static int FRAME_stand126= 169;
+ public final static int FRAME_stand127= 170;
+ public final static int FRAME_stand128= 171;
+ public final static int FRAME_stand129= 172;
+ public final static int FRAME_stand130= 173;
+ public final static int FRAME_stand131= 174;
+ public final static int FRAME_stand132= 175;
+ public final static int FRAME_stand133= 176;
+ public final static int FRAME_stand134= 177;
+ public final static int FRAME_stand135= 178;
+ public final static int FRAME_stand136= 179;
+ public final static int FRAME_stand137= 180;
+ public final static int FRAME_stand138= 181;
+ public final static int FRAME_stand139= 182;
+ public final static int FRAME_stand140= 183;
+ public final static int FRAME_stand141= 184;
+ public final static int FRAME_stand142= 185;
+ public final static int FRAME_stand143= 186;
+ public final static int FRAME_stand144= 187;
+ public final static int FRAME_stand145= 188;
+ public final static int FRAME_stand146= 189;
+ public final static int FRAME_stand147= 190;
+ public final static int FRAME_stand148= 191;
+ public final static int FRAME_stand149= 192;
+ public final static int FRAME_stand150= 193;
+ public final static int FRAME_stand151= 194;
+ public final static int FRAME_stand152= 195;
+ public final static int FRAME_stand201= 196;
+ public final static int FRAME_stand202= 197;
+ public final static int FRAME_stand203= 198;
+ public final static int FRAME_stand204= 199;
+ public final static int FRAME_stand205= 200;
+ public final static int FRAME_stand206= 201;
+ public final static int FRAME_stand207= 202;
+ public final static int FRAME_stand208= 203;
+ public final static int FRAME_stand209= 204;
+ public final static int FRAME_stand210= 205;
+ public final static int FRAME_stand211= 206;
+ public final static int FRAME_stand212= 207;
+ public final static int FRAME_stand213= 208;
+ public final static int FRAME_stand214= 209;
+ public final static int FRAME_stand215= 210;
+ public final static int FRAME_stand216= 211;
+ public final static int FRAME_stand217= 212;
+ public final static int FRAME_stand218= 213;
+ public final static int FRAME_stand219= 214;
+ public final static int FRAME_stand220= 215;
+ public final static int FRAME_stand221= 216;
+ public final static int FRAME_stand222= 217;
+ public final static int FRAME_stand223= 218;
+ public final static int FRAME_stand224= 219;
+ public final static int FRAME_stand225= 220;
+ public final static int FRAME_stand226= 221;
+ public final static int FRAME_stand227= 222;
+ public final static int FRAME_stand228= 223;
+ public final static int FRAME_stand229= 224;
+ public final static int FRAME_stand230= 225;
+ public final static int FRAME_stand231= 226;
+ public final static int FRAME_stand232= 227;
+ public final static int FRAME_stand233= 228;
+ public final static int FRAME_stand234= 229;
+ public final static int FRAME_stand235= 230;
+ public final static int FRAME_stand236= 231;
+ public final static int FRAME_stand237= 232;
+ public final static int FRAME_stand238= 233;
+ public final static int FRAME_stand239= 234;
+ public final static int FRAME_stand240= 235;
+ public final static int FRAME_stand241= 236;
+ public final static int FRAME_stand242= 237;
+ public final static int FRAME_stand243= 238;
+ public final static int FRAME_stand244= 239;
+ public final static int FRAME_stand245= 240;
+ public final static int FRAME_stand246= 241;
+ public final static int FRAME_stand247= 242;
+ public final static int FRAME_stand248= 243;
+ public final static int FRAME_stand249= 244;
+ public final static int FRAME_stand250= 245;
+ public final static int FRAME_stand251= 246;
+ public final static int FRAME_stand252= 247;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_attack2;
+ static int sound_attack3;
+ static int sound_death1;
+ static int sound_idle;
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_sight;
+
+ static EntInteractAdapter floater_sight= new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter floater_idle= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter floater_fire_blaster= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] start={0,0,0};
+ float[] forward={0,0,0}, right={0,0,0};
+ float[] end={0,0,0};
+ float[] dir={0,0,0};
+ int effect;
+
+ if ((self.s.frame == FRAME_attak104)
+ || (self.s.frame == FRAME_attak107))
+ effect= EF_HYPERBLASTER;
+ else
+ effect= 0;
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_FLOAT_BLASTER_1],
+ forward,
+ right,
+ start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ end[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(end, start, dir);
+
+ Monster.monster_fire_blaster(
+ self,
+ start,
+ dir,
+ 1,
+ 1000,
+ MZ2_FLOAT_BLASTER_1,
+ effect);
+
+ return true;
+ }
+ };
+
+ static mframe_t floater_frames_stand1[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t floater_move_stand1=
+ new mmove_t(
+ FRAME_stand101,
+ FRAME_stand152,
+ floater_frames_stand1,
+ null);
+
+ static mframe_t floater_frames_stand2[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t floater_move_stand2=
+ new mmove_t(
+ FRAME_stand201,
+ FRAME_stand252,
+ floater_frames_stand2,
+ null);
+
+ static EntThinkAdapter floater_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() <= 0.5)
+ self.monsterinfo.currentmove= floater_move_stand1;
+ else
+ self.monsterinfo.currentmove= floater_move_stand2;
+ return true;
+ }
+ };
+
+ static mframe_t floater_frames_activate[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t floater_move_activate=
+ new mmove_t(
+ FRAME_actvat01,
+ FRAME_actvat31,
+ floater_frames_activate,
+ null);
+
+ static EntThinkAdapter floater_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove= floater_move_stand1;
+ else
+ self.monsterinfo.currentmove= floater_move_run;
+
+ return true;
+ }
+ };
+
+ static mframe_t floater_frames_attack1[]=
+ new mframe_t[] { new mframe_t(ai_charge, 0, null), // Blaster attack)
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, floater_fire_blaster),
+ // BOOM (0, -25.8, 32.5) -- LOOP Starts
+ new mframe_t(ai_charge, 0, floater_fire_blaster),
+ new mframe_t(ai_charge, 0, floater_fire_blaster),
+ new mframe_t(ai_charge, 0, floater_fire_blaster),
+ new mframe_t(ai_charge, 0, floater_fire_blaster),
+ new mframe_t(ai_charge, 0, floater_fire_blaster),
+ new mframe_t(ai_charge, 0, floater_fire_blaster),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)
+ // -- LOOP Ends
+ };
+ static mmove_t floater_move_attack1=
+ new mmove_t(
+ FRAME_attak101,
+ FRAME_attak114,
+ floater_frames_attack1,
+ floater_run);
+
+ static float[] aim= { MELEE_DISTANCE, 0, 0 };
+
+ static EntThinkAdapter floater_wham= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ gi.sound(self, CHAN_WEAPON, sound_attack3, 1, ATTN_NORM, 0);
+ Fire.fire_hit(self, aim, 5 + Lib.rand() % 6, -50);
+ return true;
+ }
+ };
+
+ static mframe_t floater_frames_attack2[]=
+ new mframe_t[] { new mframe_t(ai_charge, 0, null), // Claws
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, floater_wham),
+ // WHAM (0, -45, 29.6) -- LOOP Starts
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ // -- LOOP Ends
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t floater_move_attack2=
+ new mmove_t(
+ FRAME_attak201,
+ FRAME_attak225,
+ floater_frames_attack2,
+ floater_run);
+
+ static EntThinkAdapter floater_zap= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward={0,0,0}, right={0,0,0};
+ float[] origin={0,0,0};
+ float[] dir={0,0,0};
+ float[] offset={0,0,0};
+
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, dir);
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ //FIXME use a flash and replace these two lines with the commented one
+ Math3D.VectorSet(offset, 18.5f, -0.9f, 10f);
+ Math3D.G_ProjectSource(self.s.origin, offset, forward, right, origin);
+ // G_ProjectSource (self.s.origin, monster_flash_offset[flash_number], forward, right, origin);
+
+ gi.sound(self, CHAN_WEAPON, sound_attack2, 1, ATTN_NORM, 0);
+
+ //FIXME use the flash, Luke
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_SPLASH);
+ gi.WriteByte(32);
+ gi.WritePosition(origin);
+ gi.WriteDir(dir);
+ gi.WriteByte(1); //sparks
+ gi.multicast(origin, MULTICAST_PVS);
+
+ T_Damage(
+ self.enemy,
+ self,
+ self,
+ dir,
+ self.enemy.s.origin,
+ vec3_origin,
+ 5 + Lib.rand() % 6,
+ -10,
+ DAMAGE_ENERGY,
+ MOD_UNKNOWN);
+ return true;
+ }
+ };
+ static mframe_t floater_frames_attack3[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, floater_zap),
+ // -- LOOP Starts
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ // -- LOOP Ends
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+
+ static mmove_t floater_move_attack3=
+ new mmove_t(
+ FRAME_attak301,
+ FRAME_attak334,
+ floater_frames_attack3,
+ floater_run);
+
+ static mframe_t floater_frames_death[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static EntThinkAdapter floater_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mmove_t floater_move_death=
+ new mmove_t(
+ FRAME_death01,
+ FRAME_death13,
+ floater_frames_death,
+ floater_dead);
+
+ static mframe_t floater_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+
+ static mmove_t floater_move_pain1=
+ new mmove_t(
+ FRAME_pain101,
+ FRAME_pain107,
+ floater_frames_pain1,
+ floater_run);
+
+ static mframe_t floater_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t floater_move_pain2=
+ new mmove_t(
+ FRAME_pain201,
+ FRAME_pain208,
+ floater_frames_pain2,
+ floater_run);
+
+ static mframe_t floater_frames_pain3[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t floater_move_pain3=
+ new mmove_t(
+ FRAME_pain301,
+ FRAME_pain312,
+ floater_frames_pain3,
+ floater_run);
+
+ static mframe_t floater_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null)};
+ static mmove_t floater_move_walk=
+ new mmove_t(FRAME_stand101, FRAME_stand152, floater_frames_walk, null);
+
+ static mframe_t floater_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 13, null)};
+ static mmove_t floater_move_run=
+ new mmove_t(FRAME_stand101, FRAME_stand152, floater_frames_run, null);
+
+ static EntThinkAdapter floater_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= floater_move_walk;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter floater_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= floater_move_attack1;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter floater_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if (Lib.random() < 0.5)
+ self.monsterinfo.currentmove= floater_move_attack3;
+ else
+ self.monsterinfo.currentmove= floater_move_attack2;
+ return true;
+ }
+ };
+
+ static EntPainAdapter floater_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ int n;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ n= (Lib.rand() + 1) % 3;
+ if (n == 0) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= floater_move_pain1;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= floater_move_pain2;
+ }
+ return;
+ }
+ };
+
+ static EntDieAdapter floater_die= new EntDieAdapter() {
+
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ gi.sound(self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
+ BecomeExplosion1(self);
+
+ }
+ };
+
+ /*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_floater(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_attack2= gi.soundindex("floater/fltatck2.wav");
+ sound_attack3= gi.soundindex("floater/fltatck3.wav");
+ sound_death1= gi.soundindex("floater/fltdeth1.wav");
+ sound_idle= gi.soundindex("floater/fltidle1.wav");
+ sound_pain1= gi.soundindex("floater/fltpain1.wav");
+ sound_pain2= gi.soundindex("floater/fltpain2.wav");
+ sound_sight= gi.soundindex("floater/fltsght1.wav");
+
+ gi.soundindex("floater/fltatck1.wav");
+
+ self.s.sound= gi.soundindex("floater/fltsrch1.wav");
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/float/tris.md2");
+ Math3D.VectorSet(self.mins, -24, -24, -24);
+ Math3D.VectorSet(self.maxs, 24, 24, 32);
+
+ self.health= 200;
+ self.gib_health= -80;
+ self.mass= 300;
+
+ self.pain= floater_pain;
+ self.die= floater_die;
+
+ self.monsterinfo.stand= floater_stand;
+ self.monsterinfo.walk= floater_walk;
+ self.monsterinfo.run= floater_run;
+ // self.monsterinfo.dodge = floater_dodge;
+ self.monsterinfo.attack= floater_attack;
+ self.monsterinfo.melee= floater_melee;
+ self.monsterinfo.sight= floater_sight;
+ self.monsterinfo.idle= floater_idle;
+
+ gi.linkentity(self);
+
+ if (Lib.random() <= 0.5)
+ self.monsterinfo.currentmove= floater_move_stand1;
+ else
+ self.monsterinfo.currentmove= floater_move_stand2;
+
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ flymonster_start.think(self);
+ }
+}
diff --git a/src/jake2/game/M_Flyer.java b/src/jake2/game/M_Flyer.java
new file mode 100644
index 0000000..acdeefc
--- /dev/null
+++ b/src/jake2/game/M_Flyer.java
@@ -0,0 +1,808 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Flyer.java,v 1.1 2004-07-07 19:59:14 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Flyer extends GamePWeapon {
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int ACTION_nothing= 0;
+ public final static int ACTION_attack1= 1;
+ public final static int ACTION_attack2= 2;
+ public final static int ACTION_run= 3;
+ public final static int ACTION_walk= 4;
+
+ public final static int FRAME_start01= 0;
+ public final static int FRAME_start02= 1;
+ public final static int FRAME_start03= 2;
+ public final static int FRAME_start04= 3;
+ public final static int FRAME_start05= 4;
+ public final static int FRAME_start06= 5;
+ public final static int FRAME_stop01= 6;
+ public final static int FRAME_stop02= 7;
+ public final static int FRAME_stop03= 8;
+ public final static int FRAME_stop04= 9;
+ public final static int FRAME_stop05= 10;
+ public final static int FRAME_stop06= 11;
+ public final static int FRAME_stop07= 12;
+ public final static int FRAME_stand01= 13;
+ public final static int FRAME_stand02= 14;
+ public final static int FRAME_stand03= 15;
+ public final static int FRAME_stand04= 16;
+ public final static int FRAME_stand05= 17;
+ public final static int FRAME_stand06= 18;
+ public final static int FRAME_stand07= 19;
+ public final static int FRAME_stand08= 20;
+ public final static int FRAME_stand09= 21;
+ public final static int FRAME_stand10= 22;
+ public final static int FRAME_stand11= 23;
+ public final static int FRAME_stand12= 24;
+ public final static int FRAME_stand13= 25;
+ public final static int FRAME_stand14= 26;
+ public final static int FRAME_stand15= 27;
+ public final static int FRAME_stand16= 28;
+ public final static int FRAME_stand17= 29;
+ public final static int FRAME_stand18= 30;
+ public final static int FRAME_stand19= 31;
+ public final static int FRAME_stand20= 32;
+ public final static int FRAME_stand21= 33;
+ public final static int FRAME_stand22= 34;
+ public final static int FRAME_stand23= 35;
+ public final static int FRAME_stand24= 36;
+ public final static int FRAME_stand25= 37;
+ public final static int FRAME_stand26= 38;
+ public final static int FRAME_stand27= 39;
+ public final static int FRAME_stand28= 40;
+ public final static int FRAME_stand29= 41;
+ public final static int FRAME_stand30= 42;
+ public final static int FRAME_stand31= 43;
+ public final static int FRAME_stand32= 44;
+ public final static int FRAME_stand33= 45;
+ public final static int FRAME_stand34= 46;
+ public final static int FRAME_stand35= 47;
+ public final static int FRAME_stand36= 48;
+ public final static int FRAME_stand37= 49;
+ public final static int FRAME_stand38= 50;
+ public final static int FRAME_stand39= 51;
+ public final static int FRAME_stand40= 52;
+ public final static int FRAME_stand41= 53;
+ public final static int FRAME_stand42= 54;
+ public final static int FRAME_stand43= 55;
+ public final static int FRAME_stand44= 56;
+ public final static int FRAME_stand45= 57;
+ public final static int FRAME_attak101= 58;
+ public final static int FRAME_attak102= 59;
+ public final static int FRAME_attak103= 60;
+ public final static int FRAME_attak104= 61;
+ public final static int FRAME_attak105= 62;
+ public final static int FRAME_attak106= 63;
+ public final static int FRAME_attak107= 64;
+ public final static int FRAME_attak108= 65;
+ public final static int FRAME_attak109= 66;
+ public final static int FRAME_attak110= 67;
+ public final static int FRAME_attak111= 68;
+ public final static int FRAME_attak112= 69;
+ public final static int FRAME_attak113= 70;
+ public final static int FRAME_attak114= 71;
+ public final static int FRAME_attak115= 72;
+ public final static int FRAME_attak116= 73;
+ public final static int FRAME_attak117= 74;
+ public final static int FRAME_attak118= 75;
+ public final static int FRAME_attak119= 76;
+ public final static int FRAME_attak120= 77;
+ public final static int FRAME_attak121= 78;
+ public final static int FRAME_attak201= 79;
+ public final static int FRAME_attak202= 80;
+ public final static int FRAME_attak203= 81;
+ public final static int FRAME_attak204= 82;
+ public final static int FRAME_attak205= 83;
+ public final static int FRAME_attak206= 84;
+ public final static int FRAME_attak207= 85;
+ public final static int FRAME_attak208= 86;
+ public final static int FRAME_attak209= 87;
+ public final static int FRAME_attak210= 88;
+ public final static int FRAME_attak211= 89;
+ public final static int FRAME_attak212= 90;
+ public final static int FRAME_attak213= 91;
+ public final static int FRAME_attak214= 92;
+ public final static int FRAME_attak215= 93;
+ public final static int FRAME_attak216= 94;
+ public final static int FRAME_attak217= 95;
+ public final static int FRAME_bankl01= 96;
+ public final static int FRAME_bankl02= 97;
+ public final static int FRAME_bankl03= 98;
+ public final static int FRAME_bankl04= 99;
+ public final static int FRAME_bankl05= 100;
+ public final static int FRAME_bankl06= 101;
+ public final static int FRAME_bankl07= 102;
+ public final static int FRAME_bankr01= 103;
+ public final static int FRAME_bankr02= 104;
+ public final static int FRAME_bankr03= 105;
+ public final static int FRAME_bankr04= 106;
+ public final static int FRAME_bankr05= 107;
+ public final static int FRAME_bankr06= 108;
+ public final static int FRAME_bankr07= 109;
+ public final static int FRAME_rollf01= 110;
+ public final static int FRAME_rollf02= 111;
+ public final static int FRAME_rollf03= 112;
+ public final static int FRAME_rollf04= 113;
+ public final static int FRAME_rollf05= 114;
+ public final static int FRAME_rollf06= 115;
+ public final static int FRAME_rollf07= 116;
+ public final static int FRAME_rollf08= 117;
+ public final static int FRAME_rollf09= 118;
+ public final static int FRAME_rollr01= 119;
+ public final static int FRAME_rollr02= 120;
+ public final static int FRAME_rollr03= 121;
+ public final static int FRAME_rollr04= 122;
+ public final static int FRAME_rollr05= 123;
+ public final static int FRAME_rollr06= 124;
+ public final static int FRAME_rollr07= 125;
+ public final static int FRAME_rollr08= 126;
+ public final static int FRAME_rollr09= 127;
+ public final static int FRAME_defens01= 128;
+ public final static int FRAME_defens02= 129;
+ public final static int FRAME_defens03= 130;
+ public final static int FRAME_defens04= 131;
+ public final static int FRAME_defens05= 132;
+ public final static int FRAME_defens06= 133;
+ public final static int FRAME_pain101= 134;
+ public final static int FRAME_pain102= 135;
+ public final static int FRAME_pain103= 136;
+ public final static int FRAME_pain104= 137;
+ public final static int FRAME_pain105= 138;
+ public final static int FRAME_pain106= 139;
+ public final static int FRAME_pain107= 140;
+ public final static int FRAME_pain108= 141;
+ public final static int FRAME_pain109= 142;
+ public final static int FRAME_pain201= 143;
+ public final static int FRAME_pain202= 144;
+ public final static int FRAME_pain203= 145;
+ public final static int FRAME_pain204= 146;
+ public final static int FRAME_pain301= 147;
+ public final static int FRAME_pain302= 148;
+ public final static int FRAME_pain303= 149;
+ public final static int FRAME_pain304= 150;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int nextmove; // Used for start/stop frames
+
+ static int sound_sight;
+ static int sound_idle;
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_slash;
+ static int sound_sproing;
+ static int sound_die;
+
+ public static EntInteractAdapter flyer_sight= new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_idle= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_pop_blades= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_sproing, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t flyer_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t flyer_move_stand=
+ new mmove_t(FRAME_stand01, FRAME_stand45, flyer_frames_stand, null);
+
+ static mframe_t flyer_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null)};
+
+ static mmove_t flyer_move_walk=
+ new mmove_t(FRAME_stand01, FRAME_stand45, flyer_frames_walk, null);
+
+ static mframe_t flyer_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null)};
+ static mmove_t flyer_move_run=
+ new mmove_t(FRAME_stand01, FRAME_stand45, flyer_frames_run, null);
+
+ static EntThinkAdapter flyer_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND)!=0)
+ self.monsterinfo.currentmove= flyer_move_stand;
+ else
+ self.monsterinfo.currentmove= flyer_move_run;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flyer_move_walk;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flyer_move_stand;
+ return true;
+ }
+ };
+ static EntThinkAdapter flyer_nextmove= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (nextmove == ACTION_attack1)
+ self.monsterinfo.currentmove= flyer_move_start_melee;
+ else if (nextmove == ACTION_attack2)
+ self.monsterinfo.currentmove= flyer_move_attack2;
+ else if (nextmove == ACTION_run)
+ self.monsterinfo.currentmove= flyer_move_run;
+ return true;
+ }
+ };
+ static mframe_t flyer_frames_start[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, flyer_nextmove)};
+ static mmove_t flyer_move_start=
+ new mmove_t(FRAME_start01, FRAME_start06, flyer_frames_start, null);
+
+ static mframe_t flyer_frames_stop[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, flyer_nextmove)};
+ static mmove_t flyer_move_stop=
+ new mmove_t(FRAME_stop01, FRAME_stop07, flyer_frames_stop, null);
+ static EntThinkAdapter flyer_stop= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flyer_move_stop;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_start= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove= flyer_move_start;
+ return true;
+ }
+ };
+
+ static mframe_t flyer_frames_rollright[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_rollright=
+ new mmove_t(FRAME_rollr01, FRAME_rollr09, flyer_frames_rollright, null);
+
+ static mframe_t flyer_frames_rollleft[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_rollleft=
+ new mmove_t(FRAME_rollf01, FRAME_rollf09, flyer_frames_rollleft, null);
+
+ static mframe_t flyer_frames_pain3[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_pain3=
+ new mmove_t(FRAME_pain301, FRAME_pain304, flyer_frames_pain3, flyer_run);
+
+ static mframe_t flyer_frames_pain2[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_pain2=
+ new mmove_t(FRAME_pain201, FRAME_pain204, flyer_frames_pain2, flyer_run);
+
+ static mframe_t flyer_frames_pain1[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_pain1=
+ new mmove_t(FRAME_pain101, FRAME_pain109, flyer_frames_pain1, flyer_run);
+
+ static mframe_t flyer_frames_defense[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // Hold this frame
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_defense=
+ new mmove_t(FRAME_defens01, FRAME_defens06, flyer_frames_defense, null);
+
+ static mframe_t flyer_frames_bankright[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_bankright=
+ new mmove_t(FRAME_bankr01, FRAME_bankr07, flyer_frames_bankright, null);
+
+ static mframe_t flyer_frames_bankleft[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t flyer_move_bankleft=
+ new mmove_t(FRAME_bankl01, FRAME_bankl07, flyer_frames_bankleft, null);
+
+ static void flyer_fire(edict_t self, int flash_number) {
+ float[] start={0,0,0};
+
+ float[] forward={0,0,0}, right={0,0,0};
+ float[] end={0,0,0};
+ float[] dir={0,0,0};
+ int effect;
+
+ if ((self.s.frame == FRAME_attak204)
+ || (self.s.frame == FRAME_attak207)
+ || (self.s.frame == FRAME_attak210))
+ effect= EF_HYPERBLASTER;
+ else
+ effect= 0;
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ end[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(end, start, dir);
+
+ Monster.monster_fire_blaster(self, start, dir, 1, 1000, flash_number, effect);
+ }
+ static EntThinkAdapter flyer_fireleft= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ flyer_fire(self, MZ2_FLYER_BLASTER_1);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_fireright= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ flyer_fire(self, MZ2_FLYER_BLASTER_2);
+ return true;
+ }
+ };
+
+ static mframe_t flyer_frames_attack2[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -10, flyer_fireleft),
+ // left gun
+ new mframe_t(ai_charge, -10, flyer_fireright), // right gun
+ new mframe_t(ai_charge, -10, flyer_fireleft), // left gun
+ new mframe_t(ai_charge, -10, flyer_fireright), // right gun
+ new mframe_t(ai_charge, -10, flyer_fireleft), // left gun
+ new mframe_t(ai_charge, -10, flyer_fireright), // right gun
+ new mframe_t(ai_charge, -10, flyer_fireleft), // left gun
+ new mframe_t(ai_charge, -10, flyer_fireright), // right gun
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t flyer_move_attack2=
+ new mmove_t(FRAME_attak201, FRAME_attak217, flyer_frames_attack2, flyer_run);
+
+ static EntThinkAdapter flyer_slash_left= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim={0,0,0};
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.mins[0], 0);
+ Fire.fire_hit(self, aim, 5, 0);
+ gi.sound(self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_slash_right= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim={0,0,0};
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.maxs[0], 0);
+ Fire.fire_hit(self, aim, 5, 0);
+ gi.sound(self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+ static EntThinkAdapter flyer_loop_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ /* if (random() <= 0.5)
+ self.monsterinfo.currentmove = flyer_move_attack1;
+ else */
+ self.monsterinfo.currentmove= flyer_move_loop_melee;
+ return true;
+ }
+ };
+
+ static mframe_t flyer_frames_start_melee[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, flyer_pop_blades),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t flyer_move_start_melee=
+ new mmove_t(FRAME_attak101, FRAME_attak106, flyer_frames_start_melee, flyer_loop_melee);
+
+ static mframe_t flyer_frames_end_melee[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t flyer_move_end_melee=
+ new mmove_t(FRAME_attak119, FRAME_attak121, flyer_frames_end_melee, flyer_run);
+
+ static mframe_t flyer_frames_loop_melee[]=
+ new mframe_t[] { new mframe_t(ai_charge, 0, null), // Loop Start
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, flyer_slash_left), // Left Wing Strike
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, flyer_slash_right), // Right Wing Strike
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null) // Loop Ends
+
+ };
+
+ static EntThinkAdapter flyer_check_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (range(self, self.enemy) == RANGE_MELEE)
+ if (Lib.random() <= 0.8)
+ self.monsterinfo.currentmove= flyer_move_loop_melee;
+ else
+ self.monsterinfo.currentmove= flyer_move_end_melee;
+ else
+ self.monsterinfo.currentmove= flyer_move_end_melee;
+ return true;
+ }
+ };
+
+ static mmove_t flyer_move_loop_melee=
+ new mmove_t(FRAME_attak107, FRAME_attak118, flyer_frames_loop_melee, flyer_check_melee);
+
+
+ static EntThinkAdapter flyer_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ /* if (random() <= 0.5)
+ self.monsterinfo.currentmove = flyer_move_attack1;
+ else */
+ self.monsterinfo.currentmove= flyer_move_attack2;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter flyer_setstart= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ nextmove= ACTION_run;
+ self.monsterinfo.currentmove= flyer_move_start;
+ return true;
+ }
+ };
+
+
+
+ static EntThinkAdapter flyer_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ // flyer.nextmove = ACTION_attack1;
+ // self.monsterinfo.currentmove = flyer_move_stop;
+ self.monsterinfo.currentmove= flyer_move_start_melee;
+ return true;
+ }
+ };
+
+
+ static EntPainAdapter flyer_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ int n;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time= level.time + 3;
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ n= Lib.rand() % 3;
+ if (n == 0) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= flyer_move_pain1;
+ } else if (n == 1) {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= flyer_move_pain2;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove= flyer_move_pain3;
+ }
+
+ }
+ };
+ static EntDieAdapter flyer_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+ BecomeExplosion1(self);
+ }
+ };
+
+ /*QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ public static void SP_monster_flyer(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ // fix a map bug in jail5.bsp
+ if (0 == Lib.stricmp(level.mapname, "jail5") && (self.s.origin[2] == -104)) {
+ self.targetname= self.target;
+ self.target= null;
+ }
+
+ sound_sight= gi.soundindex("flyer/flysght1.wav");
+ sound_idle= gi.soundindex("flyer/flysrch1.wav");
+ sound_pain1= gi.soundindex("flyer/flypain1.wav");
+ sound_pain2= gi.soundindex("flyer/flypain2.wav");
+ sound_slash= gi.soundindex("flyer/flyatck2.wav");
+ sound_sproing= gi.soundindex("flyer/flyatck1.wav");
+ sound_die= gi.soundindex("flyer/flydeth1.wav");
+
+ gi.soundindex("flyer/flyatck3.wav");
+
+ self.s.modelindex= gi.modelindex("models/monsters/flyer/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+
+ self.s.sound= gi.soundindex("flyer/flyidle1.wav");
+
+ self.health= 50;
+ self.mass= 50;
+
+ self.pain= flyer_pain;
+ self.die= flyer_die;
+
+ self.monsterinfo.stand= flyer_stand;
+ self.monsterinfo.walk= flyer_walk;
+ self.monsterinfo.run= flyer_run;
+ self.monsterinfo.attack= flyer_attack;
+ self.monsterinfo.melee= flyer_melee;
+ self.monsterinfo.sight= flyer_sight;
+ self.monsterinfo.idle= flyer_idle;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove= flyer_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ flymonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Gladiator.java b/src/jake2/game/M_Gladiator.java
new file mode 100644
index 0000000..9acfd73
--- /dev/null
+++ b/src/jake2/game/M_Gladiator.java
@@ -0,0 +1,570 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Gladiator.java,v 1.1 2004-07-07 19:59:14 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Gladiator extends Game {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_stand1= 0;
+ public final static int FRAME_stand2= 1;
+ public final static int FRAME_stand3= 2;
+ public final static int FRAME_stand4= 3;
+ public final static int FRAME_stand5= 4;
+ public final static int FRAME_stand6= 5;
+ public final static int FRAME_stand7= 6;
+ public final static int FRAME_walk1= 7;
+ public final static int FRAME_walk2= 8;
+ public final static int FRAME_walk3= 9;
+ public final static int FRAME_walk4= 10;
+ public final static int FRAME_walk5= 11;
+ public final static int FRAME_walk6= 12;
+ public final static int FRAME_walk7= 13;
+ public final static int FRAME_walk8= 14;
+ public final static int FRAME_walk9= 15;
+ public final static int FRAME_walk10= 16;
+ public final static int FRAME_walk11= 17;
+ public final static int FRAME_walk12= 18;
+ public final static int FRAME_walk13= 19;
+ public final static int FRAME_walk14= 20;
+ public final static int FRAME_walk15= 21;
+ public final static int FRAME_walk16= 22;
+ public final static int FRAME_run1= 23;
+ public final static int FRAME_run2= 24;
+ public final static int FRAME_run3= 25;
+ public final static int FRAME_run4= 26;
+ public final static int FRAME_run5= 27;
+ public final static int FRAME_run6= 28;
+ public final static int FRAME_melee1= 29;
+ public final static int FRAME_melee2= 30;
+ public final static int FRAME_melee3= 31;
+ public final static int FRAME_melee4= 32;
+ public final static int FRAME_melee5= 33;
+ public final static int FRAME_melee6= 34;
+ public final static int FRAME_melee7= 35;
+ public final static int FRAME_melee8= 36;
+ public final static int FRAME_melee9= 37;
+ public final static int FRAME_melee10= 38;
+ public final static int FRAME_melee11= 39;
+ public final static int FRAME_melee12= 40;
+ public final static int FRAME_melee13= 41;
+ public final static int FRAME_melee14= 42;
+ public final static int FRAME_melee15= 43;
+ public final static int FRAME_melee16= 44;
+ public final static int FRAME_melee17= 45;
+ public final static int FRAME_attack1= 46;
+ public final static int FRAME_attack2= 47;
+ public final static int FRAME_attack3= 48;
+ public final static int FRAME_attack4= 49;
+ public final static int FRAME_attack5= 50;
+ public final static int FRAME_attack6= 51;
+ public final static int FRAME_attack7= 52;
+ public final static int FRAME_attack8= 53;
+ public final static int FRAME_attack9= 54;
+ public final static int FRAME_pain1= 55;
+ public final static int FRAME_pain2= 56;
+ public final static int FRAME_pain3= 57;
+ public final static int FRAME_pain4= 58;
+ public final static int FRAME_pain5= 59;
+ public final static int FRAME_pain6= 60;
+ public final static int FRAME_death1= 61;
+ public final static int FRAME_death2= 62;
+ public final static int FRAME_death3= 63;
+ public final static int FRAME_death4= 64;
+ public final static int FRAME_death5= 65;
+ public final static int FRAME_death6= 66;
+ public final static int FRAME_death7= 67;
+ public final static int FRAME_death8= 68;
+ public final static int FRAME_death9= 69;
+ public final static int FRAME_death10= 70;
+ public final static int FRAME_death11= 71;
+ public final static int FRAME_death12= 72;
+ public final static int FRAME_death13= 73;
+ public final static int FRAME_death14= 74;
+ public final static int FRAME_death15= 75;
+ public final static int FRAME_death16= 76;
+ public final static int FRAME_death17= 77;
+ public final static int FRAME_death18= 78;
+ public final static int FRAME_death19= 79;
+ public final static int FRAME_death20= 80;
+ public final static int FRAME_death21= 81;
+ public final static int FRAME_death22= 82;
+ public final static int FRAME_painup1= 83;
+ public final static int FRAME_painup2= 84;
+ public final static int FRAME_painup3= 85;
+ public final static int FRAME_painup4= 86;
+ public final static int FRAME_painup5= 87;
+ public final static int FRAME_painup6= 88;
+ public final static int FRAME_painup7= 89;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_die;
+ static int sound_gun;
+ static int sound_cleaver_swing;
+ static int sound_cleaver_hit;
+ static int sound_cleaver_miss;
+ static int sound_idle;
+ static int sound_search;
+ static int sound_sight;
+
+ static EntThinkAdapter gladiator_idle= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+ static EntInteractAdapter gladiator_sight= new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter gladiator_search= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter gladiator_cleaver_swing= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ gi.sound(self, CHAN_WEAPON, sound_cleaver_swing, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t gladiator_frames_stand[]=
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t gladiator_move_stand=
+ new mmove_t(FRAME_stand1, FRAME_stand7, gladiator_frames_stand, null);
+
+ static EntThinkAdapter gladiator_stand= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.monsterinfo.currentmove= gladiator_move_stand;
+ return true;
+ }
+ };
+
+ static mframe_t gladiator_frames_walk[]=
+ new mframe_t[] {
+ new mframe_t(ai_walk, 15, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 12, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 8, null)};
+ static mmove_t gladiator_move_walk=
+ new mmove_t(FRAME_walk1, FRAME_walk16, gladiator_frames_walk, null);
+
+ static EntThinkAdapter gladiator_walk= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.monsterinfo.currentmove= gladiator_move_walk;
+
+ return true;
+ }
+ };
+
+ static mframe_t gladiator_frames_run[]=
+ new mframe_t[] {
+ new mframe_t(ai_run, 23, null),
+ new mframe_t(ai_run, 14, null),
+ new mframe_t(ai_run, 14, null),
+ new mframe_t(ai_run, 21, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 13, null)};
+ static mmove_t gladiator_move_run=
+ new mmove_t(FRAME_run1, FRAME_run6, gladiator_frames_run, null);
+
+ static EntThinkAdapter gladiator_run= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove= gladiator_move_stand;
+ else
+ self.monsterinfo.currentmove= gladiator_move_run;
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter GaldiatorMelee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] aim= { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.mins[0], -4);
+ if (Fire.fire_hit(self, aim, (20 + (Lib.rand() % 5)), 300))
+ gi.sound(self, CHAN_AUTO, sound_cleaver_hit, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_AUTO, sound_cleaver_miss, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t gladiator_frames_attack_melee[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, gladiator_cleaver_swing),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, GaldiatorMelee),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, gladiator_cleaver_swing),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, GaldiatorMelee),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+
+ static mmove_t gladiator_move_attack_melee=
+ new mmove_t(
+ FRAME_melee1,
+ FRAME_melee17,
+ gladiator_frames_attack_melee,
+ gladiator_run);
+
+ static EntThinkAdapter gladiator_melee= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.monsterinfo.currentmove= gladiator_move_attack_melee;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter GladiatorGun= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] start= { 0, 0, 0 };
+
+ float[] dir= { 0, 0, 0 };
+ float[] forward= { 0, 0, 0 }, right= { 0, 0, 0 };
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(
+ self.s.origin,
+ monster_flash_offset[MZ2_GLADIATOR_RAILGUN_1],
+ forward,
+ right,
+ start);
+
+ // calc direction to where we targted
+ Math3D.VectorSubtract(self.pos1, start, dir);
+ Math3D.VectorNormalize(dir);
+
+ Monster.monster_fire_railgun(
+ self,
+ start,
+ dir,
+ 50,
+ 100,
+ MZ2_GLADIATOR_RAILGUN_1);
+
+ return true;
+ }
+ };
+
+ static mframe_t gladiator_frames_attack_gun[]=
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, GladiatorGun),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t gladiator_move_attack_gun=
+ new mmove_t(
+ FRAME_attack1,
+ FRAME_attack9,
+ gladiator_frames_attack_gun,
+ gladiator_run);
+
+ static EntThinkAdapter gladiator_attack= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float range;
+ float[] v={0,0,0};
+
+
+ // a small safe zone
+ Math3D.VectorSubtract(self.s.origin, self.enemy.s.origin, v);
+ range= Math3D.VectorLength(v);
+ if (range <= (MELEE_DISTANCE + 32))
+ return true;
+
+ // charge up the railgun
+ gi.sound(self, CHAN_WEAPON, sound_gun, 1, ATTN_NORM, 0);
+ Math3D.VectorCopy(self.enemy.s.origin, self.pos1);
+ //save for aiming the shot
+ self.pos1[2] += self.enemy.viewheight;
+ self.monsterinfo.currentmove= gladiator_move_attack_gun;
+ return true;
+ }
+ };
+
+ static mframe_t gladiator_frames_pain[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t gladiator_move_pain=
+ new mmove_t(
+ FRAME_pain1,
+ FRAME_pain6,
+ gladiator_frames_pain,
+ gladiator_run);
+
+ static mframe_t gladiator_frames_pain_air[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t gladiator_move_pain_air=
+ new mmove_t(
+ FRAME_painup1,
+ FRAME_painup7,
+ gladiator_frames_pain_air,
+ gladiator_run);
+
+ static EntPainAdapter gladiator_pain= new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum= 1;
+
+ if (level.time < self.pain_debounce_time) {
+ if ((self.velocity[2] > 100)
+ && (self.monsterinfo.currentmove == gladiator_move_pain))
+ self.monsterinfo.currentmove= gladiator_move_pain_air;
+ return;
+ }
+
+ self.pain_debounce_time= level.time + 3;
+
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (self.velocity[2] > 100)
+ self.monsterinfo.currentmove= gladiator_move_pain_air;
+ else
+ self.monsterinfo.currentmove= gladiator_move_pain;
+
+ }
+ };
+
+ static EntThinkAdapter gladiator_dead= new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype= MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink= 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t gladiator_frames_death[]=
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t gladiator_move_death=
+ new mmove_t(
+ FRAME_death1,
+ FRAME_death22,
+ gladiator_frames_death,
+ gladiator_dead);
+
+ static EntDieAdapter gladiator_die= new EntDieAdapter() {
+ public void die(
+ edict_t self,
+ edict_t inflictor,
+ edict_t attacker,
+ int damage,
+ float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(
+ self,
+ CHAN_VOICE,
+ gi.soundindex("misc/udeath.wav"),
+ 1,
+ ATTN_NORM,
+ 0);
+ for (n= 0; n < 2; n++)
+ ThrowGib(
+ self,
+ "models/objects/gibs/bone/tris.md2",
+ damage,
+ GIB_ORGANIC);
+ for (n= 0; n < 4; n++)
+ ThrowGib(
+ self,
+ "models/objects/gibs/sm_meat/tris.md2",
+ damage,
+ GIB_ORGANIC);
+ ThrowHead(
+ self,
+ "models/objects/gibs/head2/tris.md2",
+ damage,
+ GIB_ORGANIC);
+ self.deadflag= DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+ self.deadflag= DEAD_DEAD;
+ self.takedamage= DAMAGE_YES;
+
+ self.monsterinfo.currentmove= gladiator_move_death;
+
+ }
+ };
+
+ /*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_gladiator(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_pain1= gi.soundindex("gladiator/pain.wav");
+ sound_pain2= gi.soundindex("gladiator/gldpain2.wav");
+ sound_die= gi.soundindex("gladiator/glddeth2.wav");
+ sound_gun= gi.soundindex("gladiator/railgun.wav");
+ sound_cleaver_swing= gi.soundindex("gladiator/melee1.wav");
+ sound_cleaver_hit= gi.soundindex("gladiator/melee2.wav");
+ sound_cleaver_miss= gi.soundindex("gladiator/melee3.wav");
+ sound_idle= gi.soundindex("gladiator/gldidle1.wav");
+ sound_search= gi.soundindex("gladiator/gldsrch1.wav");
+ sound_sight= gi.soundindex("gladiator/sight.wav");
+
+ self.movetype= MOVETYPE_STEP;
+ self.solid= SOLID_BBOX;
+ self.s.modelindex= gi.modelindex("models/monsters/gladiatr/tris.md2");
+ Math3D.VectorSet(self.mins, -32, -32, -24);
+ Math3D.VectorSet(self.maxs, 32, 32, 64);
+
+ self.health= 400;
+ self.gib_health= -175;
+ self.mass= 400;
+
+ self.pain= gladiator_pain;
+ self.die= gladiator_die;
+
+ self.monsterinfo.stand= gladiator_stand;
+ self.monsterinfo.walk= gladiator_walk;
+ self.monsterinfo.run= gladiator_run;
+ self.monsterinfo.dodge= null;
+ self.monsterinfo.attack= gladiator_attack;
+ self.monsterinfo.melee= gladiator_melee;
+ self.monsterinfo.sight= gladiator_sight;
+ self.monsterinfo.idle= gladiator_idle;
+ self.monsterinfo.search= gladiator_search;
+
+ gi.linkentity(self);
+ self.monsterinfo.currentmove= gladiator_move_stand;
+ self.monsterinfo.scale= MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Gunner.java b/src/jake2/game/M_Gunner.java
new file mode 100644
index 0000000..cdff1a0
--- /dev/null
+++ b/src/jake2/game/M_Gunner.java
@@ -0,0 +1,837 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Gunner.java,v 1.1 2004-07-07 19:59:14 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Gunner extends Game {
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_stand01 = 0;
+ public final static int FRAME_stand02 = 1;
+ public final static int FRAME_stand03 = 2;
+ public final static int FRAME_stand04 = 3;
+ public final static int FRAME_stand05 = 4;
+ public final static int FRAME_stand06 = 5;
+ public final static int FRAME_stand07 = 6;
+ public final static int FRAME_stand08 = 7;
+ public final static int FRAME_stand09 = 8;
+ public final static int FRAME_stand10 = 9;
+ public final static int FRAME_stand11 = 10;
+ public final static int FRAME_stand12 = 11;
+ public final static int FRAME_stand13 = 12;
+ public final static int FRAME_stand14 = 13;
+ public final static int FRAME_stand15 = 14;
+ public final static int FRAME_stand16 = 15;
+ public final static int FRAME_stand17 = 16;
+ public final static int FRAME_stand18 = 17;
+ public final static int FRAME_stand19 = 18;
+ public final static int FRAME_stand20 = 19;
+ public final static int FRAME_stand21 = 20;
+ public final static int FRAME_stand22 = 21;
+ public final static int FRAME_stand23 = 22;
+ public final static int FRAME_stand24 = 23;
+ public final static int FRAME_stand25 = 24;
+ public final static int FRAME_stand26 = 25;
+ public final static int FRAME_stand27 = 26;
+ public final static int FRAME_stand28 = 27;
+ public final static int FRAME_stand29 = 28;
+ public final static int FRAME_stand30 = 29;
+ public final static int FRAME_stand31 = 30;
+ public final static int FRAME_stand32 = 31;
+ public final static int FRAME_stand33 = 32;
+ public final static int FRAME_stand34 = 33;
+ public final static int FRAME_stand35 = 34;
+ public final static int FRAME_stand36 = 35;
+ public final static int FRAME_stand37 = 36;
+ public final static int FRAME_stand38 = 37;
+ public final static int FRAME_stand39 = 38;
+ public final static int FRAME_stand40 = 39;
+ public final static int FRAME_stand41 = 40;
+ public final static int FRAME_stand42 = 41;
+ public final static int FRAME_stand43 = 42;
+ public final static int FRAME_stand44 = 43;
+ public final static int FRAME_stand45 = 44;
+ public final static int FRAME_stand46 = 45;
+ public final static int FRAME_stand47 = 46;
+ public final static int FRAME_stand48 = 47;
+ public final static int FRAME_stand49 = 48;
+ public final static int FRAME_stand50 = 49;
+ public final static int FRAME_stand51 = 50;
+ public final static int FRAME_stand52 = 51;
+ public final static int FRAME_stand53 = 52;
+ public final static int FRAME_stand54 = 53;
+ public final static int FRAME_stand55 = 54;
+ public final static int FRAME_stand56 = 55;
+ public final static int FRAME_stand57 = 56;
+ public final static int FRAME_stand58 = 57;
+ public final static int FRAME_stand59 = 58;
+ public final static int FRAME_stand60 = 59;
+ public final static int FRAME_stand61 = 60;
+ public final static int FRAME_stand62 = 61;
+ public final static int FRAME_stand63 = 62;
+ public final static int FRAME_stand64 = 63;
+ public final static int FRAME_stand65 = 64;
+ public final static int FRAME_stand66 = 65;
+ public final static int FRAME_stand67 = 66;
+ public final static int FRAME_stand68 = 67;
+ public final static int FRAME_stand69 = 68;
+ public final static int FRAME_stand70 = 69;
+ public final static int FRAME_walk01 = 70;
+ public final static int FRAME_walk02 = 71;
+ public final static int FRAME_walk03 = 72;
+ public final static int FRAME_walk04 = 73;
+ public final static int FRAME_walk05 = 74;
+ public final static int FRAME_walk06 = 75;
+ public final static int FRAME_walk07 = 76;
+ public final static int FRAME_walk08 = 77;
+ public final static int FRAME_walk09 = 78;
+ public final static int FRAME_walk10 = 79;
+ public final static int FRAME_walk11 = 80;
+ public final static int FRAME_walk12 = 81;
+ public final static int FRAME_walk13 = 82;
+ public final static int FRAME_walk14 = 83;
+ public final static int FRAME_walk15 = 84;
+ public final static int FRAME_walk16 = 85;
+ public final static int FRAME_walk17 = 86;
+ public final static int FRAME_walk18 = 87;
+ public final static int FRAME_walk19 = 88;
+ public final static int FRAME_walk20 = 89;
+ public final static int FRAME_walk21 = 90;
+ public final static int FRAME_walk22 = 91;
+ public final static int FRAME_walk23 = 92;
+ public final static int FRAME_walk24 = 93;
+ public final static int FRAME_run01 = 94;
+ public final static int FRAME_run02 = 95;
+ public final static int FRAME_run03 = 96;
+ public final static int FRAME_run04 = 97;
+ public final static int FRAME_run05 = 98;
+ public final static int FRAME_run06 = 99;
+ public final static int FRAME_run07 = 100;
+ public final static int FRAME_run08 = 101;
+ public final static int FRAME_runs01 = 102;
+ public final static int FRAME_runs02 = 103;
+ public final static int FRAME_runs03 = 104;
+ public final static int FRAME_runs04 = 105;
+ public final static int FRAME_runs05 = 106;
+ public final static int FRAME_runs06 = 107;
+ public final static int FRAME_attak101 = 108;
+ public final static int FRAME_attak102 = 109;
+ public final static int FRAME_attak103 = 110;
+ public final static int FRAME_attak104 = 111;
+ public final static int FRAME_attak105 = 112;
+ public final static int FRAME_attak106 = 113;
+ public final static int FRAME_attak107 = 114;
+ public final static int FRAME_attak108 = 115;
+ public final static int FRAME_attak109 = 116;
+ public final static int FRAME_attak110 = 117;
+ public final static int FRAME_attak111 = 118;
+ public final static int FRAME_attak112 = 119;
+ public final static int FRAME_attak113 = 120;
+ public final static int FRAME_attak114 = 121;
+ public final static int FRAME_attak115 = 122;
+ public final static int FRAME_attak116 = 123;
+ public final static int FRAME_attak117 = 124;
+ public final static int FRAME_attak118 = 125;
+ public final static int FRAME_attak119 = 126;
+ public final static int FRAME_attak120 = 127;
+ public final static int FRAME_attak121 = 128;
+ public final static int FRAME_attak201 = 129;
+ public final static int FRAME_attak202 = 130;
+ public final static int FRAME_attak203 = 131;
+ public final static int FRAME_attak204 = 132;
+ public final static int FRAME_attak205 = 133;
+ public final static int FRAME_attak206 = 134;
+ public final static int FRAME_attak207 = 135;
+ public final static int FRAME_attak208 = 136;
+ public final static int FRAME_attak209 = 137;
+ public final static int FRAME_attak210 = 138;
+ public final static int FRAME_attak211 = 139;
+ public final static int FRAME_attak212 = 140;
+ public final static int FRAME_attak213 = 141;
+ public final static int FRAME_attak214 = 142;
+ public final static int FRAME_attak215 = 143;
+ public final static int FRAME_attak216 = 144;
+ public final static int FRAME_attak217 = 145;
+ public final static int FRAME_attak218 = 146;
+ public final static int FRAME_attak219 = 147;
+ public final static int FRAME_attak220 = 148;
+ public final static int FRAME_attak221 = 149;
+ public final static int FRAME_attak222 = 150;
+ public final static int FRAME_attak223 = 151;
+ public final static int FRAME_attak224 = 152;
+ public final static int FRAME_attak225 = 153;
+ public final static int FRAME_attak226 = 154;
+ public final static int FRAME_attak227 = 155;
+ public final static int FRAME_attak228 = 156;
+ public final static int FRAME_attak229 = 157;
+ public final static int FRAME_attak230 = 158;
+ public final static int FRAME_pain101 = 159;
+ public final static int FRAME_pain102 = 160;
+ public final static int FRAME_pain103 = 161;
+ public final static int FRAME_pain104 = 162;
+ public final static int FRAME_pain105 = 163;
+ public final static int FRAME_pain106 = 164;
+ public final static int FRAME_pain107 = 165;
+ public final static int FRAME_pain108 = 166;
+ public final static int FRAME_pain109 = 167;
+ public final static int FRAME_pain110 = 168;
+ public final static int FRAME_pain111 = 169;
+ public final static int FRAME_pain112 = 170;
+ public final static int FRAME_pain113 = 171;
+ public final static int FRAME_pain114 = 172;
+ public final static int FRAME_pain115 = 173;
+ public final static int FRAME_pain116 = 174;
+ public final static int FRAME_pain117 = 175;
+ public final static int FRAME_pain118 = 176;
+ public final static int FRAME_pain201 = 177;
+ public final static int FRAME_pain202 = 178;
+ public final static int FRAME_pain203 = 179;
+ public final static int FRAME_pain204 = 180;
+ public final static int FRAME_pain205 = 181;
+ public final static int FRAME_pain206 = 182;
+ public final static int FRAME_pain207 = 183;
+ public final static int FRAME_pain208 = 184;
+ public final static int FRAME_pain301 = 185;
+ public final static int FRAME_pain302 = 186;
+ public final static int FRAME_pain303 = 187;
+ public final static int FRAME_pain304 = 188;
+ public final static int FRAME_pain305 = 189;
+ public final static int FRAME_death01 = 190;
+ public final static int FRAME_death02 = 191;
+ public final static int FRAME_death03 = 192;
+ public final static int FRAME_death04 = 193;
+ public final static int FRAME_death05 = 194;
+ public final static int FRAME_death06 = 195;
+ public final static int FRAME_death07 = 196;
+ public final static int FRAME_death08 = 197;
+ public final static int FRAME_death09 = 198;
+ public final static int FRAME_death10 = 199;
+ public final static int FRAME_death11 = 200;
+ public final static int FRAME_duck01 = 201;
+ public final static int FRAME_duck02 = 202;
+ public final static int FRAME_duck03 = 203;
+ public final static int FRAME_duck04 = 204;
+ public final static int FRAME_duck05 = 205;
+ public final static int FRAME_duck06 = 206;
+ public final static int FRAME_duck07 = 207;
+ public final static int FRAME_duck08 = 208;
+
+ public final static float MODEL_SCALE = 1.150000f;
+
+ static int sound_pain;
+ static int sound_pain2;
+ static int sound_death;
+ static int sound_idle;
+ static int sound_open;
+ static int sound_search;
+ static int sound_sight;
+
+ static EntThinkAdapter xxx = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ return true;
+ }
+ };
+ static EntThinkAdapter gunner_idlesound = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntInteractAdapter gunner_sight = new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter gunner_search = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_fidget[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, gunner_idlesound),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+
+ static EntThinkAdapter gunner_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = gunner_move_stand;
+ return true;
+ }
+ };
+ static mmove_t gunner_move_fidget = new mmove_t(FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand);
+
+ static EntThinkAdapter gunner_fidget = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ return true;
+ if (Lib.random() <= 0.05)
+ self.monsterinfo.currentmove = gunner_move_fidget;
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, gunner_fidget),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, gunner_fidget),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, gunner_fidget)};
+ static mmove_t gunner_move_stand = new mmove_t(FRAME_stand01, FRAME_stand30, gunner_frames_stand, null);
+
+ static mframe_t gunner_frames_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 4, null)};
+ static mmove_t gunner_move_walk = new mmove_t(FRAME_walk07, FRAME_walk19, gunner_frames_walk, null);
+
+ static EntThinkAdapter gunner_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = gunner_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 26, null),
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 9, null),
+ new mframe_t(ai_run, 15, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 13, null),
+ new mframe_t(ai_run, 6, null)};
+
+ static mmove_t gunner_move_run = new mmove_t(FRAME_run01, FRAME_run08, gunner_frames_run, null);
+
+ static EntThinkAdapter gunner_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove = gunner_move_stand;
+ else
+ self.monsterinfo.currentmove = gunner_move_run;
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_runandshoot[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 32, null),
+ new mframe_t(ai_run, 15, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 18, null),
+ new mframe_t(ai_run, 8, null),
+ new mframe_t(ai_run, 20, null)};
+
+ static mmove_t gunner_move_runandshoot = new mmove_t(FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, null);
+
+ static EntThinkAdapter gunner_runandshoot = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = gunner_move_runandshoot;
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_pain3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 1, null)};
+ static mmove_t gunner_move_pain3 = new mmove_t(FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run);
+
+ static mframe_t gunner_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 11, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -7, null)};
+ static mmove_t gunner_move_pain2 = new mmove_t(FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run);
+
+ static mframe_t gunner_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t gunner_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run);
+
+ static EntPainAdapter gunner_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ if ((Lib.rand() & 1) != 0)
+ gi.sound(self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (damage <= 10)
+ self.monsterinfo.currentmove = gunner_move_pain3;
+ else if (damage <= 25)
+ self.monsterinfo.currentmove = gunner_move_pain2;
+ else
+ self.monsterinfo.currentmove = gunner_move_pain1;
+
+ }
+ };
+
+ static EntThinkAdapter gunner_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink = 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_death[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 8, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t gunner_move_death = new mmove_t(FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead);
+
+ static EntDieAdapter gunner_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.currentmove = gunner_move_death;
+ }
+ };
+ static EntThinkAdapter gunner_duck_down = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_DUCKED) != 0)
+ return true;
+ self.monsterinfo.aiflags |= AI_DUCKED;
+ if (skill.value >= 2) {
+ if (Lib.random() > 0.5)
+ GunnerGrenade.think(self);
+ }
+
+ self.maxs[2] -= 32;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.pausetime = level.time + 1;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter gunner_duck_hold = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter gunner_duck_up = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.aiflags &= ~AI_DUCKED;
+ self.maxs[2] += 32;
+ self.takedamage = DAMAGE_AIM;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_duck[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 1, gunner_duck_down),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, gunner_duck_hold),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 0, gunner_duck_up),
+ new mframe_t(ai_move, -1, null)};
+ static mmove_t gunner_move_duck = new mmove_t(FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run);
+
+ static EntDodgeAdapter gunner_dodge = new EntDodgeAdapter() {
+ public void dodge(edict_t self, edict_t attacker, float eta) {
+ if (Lib.random() > 0.25)
+ return;
+
+ if (self.enemy == null)
+ self.enemy = attacker;
+
+ self.monsterinfo.currentmove = gunner_move_duck;
+ }
+ };
+
+ static EntThinkAdapter gunner_opengun = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter GunnerFire = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] start = { 0, 0, 0 };
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 };
+ float[] target = { 0, 0, 0 };
+ float[] aim = { 0, 0, 0 };
+ int flash_number;
+
+ flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self.s.frame - FRAME_attak216);
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ // project enemy back a bit and target there
+ Math3D.VectorCopy(self.enemy.s.origin, target);
+ Math3D.VectorMA(target, -0.2f, self.enemy.velocity, target);
+ target[2] += self.enemy.viewheight;
+
+ Math3D.VectorSubtract(target, start, aim);
+ Math3D.VectorNormalize(aim);
+ Monster.monster_fire_bullet(self, start, aim, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter GunnerGrenade = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] start={0,0,0};
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 };
+ float[] aim = { 0, 0, 0 };
+ int flash_number;
+
+ if (self.s.frame == FRAME_attak105)
+ flash_number = MZ2_GUNNER_GRENADE_1;
+ else if (self.s.frame == FRAME_attak108)
+ flash_number = MZ2_GUNNER_GRENADE_2;
+ else if (self.s.frame == FRAME_attak111)
+ flash_number = MZ2_GUNNER_GRENADE_3;
+ else // (self.s.frame == FRAME_attak114)
+ flash_number = MZ2_GUNNER_GRENADE_4;
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ //FIXME : do a spread -225 -75 75 225 degrees around forward
+ Math3D.VectorCopy(forward, aim);
+
+ Monster.monster_fire_grenade(self, start, aim, 50, 600, flash_number);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter gunner_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (range(self, self.enemy) == RANGE_MELEE) {
+ self.monsterinfo.currentmove = gunner_move_attack_chain;
+ } else {
+ if (Lib.random() <= 0.5)
+ self.monsterinfo.currentmove = gunner_move_attack_grenade;
+ else
+ self.monsterinfo.currentmove = gunner_move_attack_chain;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter gunner_fire_chain = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = gunner_move_fire_chain;
+ return true;
+ }
+ };
+
+ static mframe_t gunner_frames_attack_chain[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, gunner_opengun),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t gunner_move_attack_chain =
+ new mmove_t(FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain);
+
+ static mframe_t gunner_frames_fire_chain[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, GunnerFire),
+ new mframe_t(ai_charge, 0, GunnerFire),
+ new mframe_t(ai_charge, 0, GunnerFire),
+ new mframe_t(ai_charge, 0, GunnerFire),
+ new mframe_t(ai_charge, 0, GunnerFire),
+ new mframe_t(ai_charge, 0, GunnerFire),
+ new mframe_t(ai_charge, 0, GunnerFire),
+ new mframe_t(ai_charge, 0, GunnerFire)};
+
+ static EntThinkAdapter gunner_refire_chain = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.enemy.health > 0)
+ if (visible(self, self.enemy))
+ if (Lib.random() <= 0.5) {
+ self.monsterinfo.currentmove = gunner_move_fire_chain;
+ return true;
+ }
+ self.monsterinfo.currentmove = gunner_move_endfire_chain;
+ return true;
+ }
+ };
+
+ static mmove_t gunner_move_fire_chain = new mmove_t(FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain);
+
+ static mframe_t gunner_frames_endfire_chain[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t gunner_move_endfire_chain = new mmove_t(FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run);
+
+ static mframe_t gunner_frames_attack_grenade[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, GunnerGrenade),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, GunnerGrenade),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, GunnerGrenade),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, GunnerGrenade),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t gunner_move_attack_grenade = new mmove_t(FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run);
+
+ /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_gunner(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_death = gi.soundindex("gunner/death1.wav");
+ sound_pain = gi.soundindex("gunner/gunpain2.wav");
+ sound_pain2 = gi.soundindex("gunner/gunpain1.wav");
+ sound_idle = gi.soundindex("gunner/gunidle1.wav");
+ sound_open = gi.soundindex("gunner/gunatck1.wav");
+ sound_search = gi.soundindex("gunner/gunsrch1.wav");
+ sound_sight = gi.soundindex("gunner/sight1.wav");
+
+ gi.soundindex("gunner/gunatck2.wav");
+ gi.soundindex("gunner/gunatck3.wav");
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/gunner/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+
+ self.health = 175;
+ self.gib_health = -70;
+ self.mass = 200;
+
+ self.pain = gunner_pain;
+ self.die = gunner_die;
+
+ self.monsterinfo.stand = gunner_stand;
+ self.monsterinfo.walk = gunner_walk;
+ self.monsterinfo.run = gunner_run;
+ self.monsterinfo.dodge = gunner_dodge;
+ self.monsterinfo.attack = gunner_attack;
+ self.monsterinfo.melee = null;
+ self.monsterinfo.sight = gunner_sight;
+ self.monsterinfo.search = gunner_search;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = gunner_move_stand;
+ self.monsterinfo.scale = MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Hover.java b/src/jake2/game/M_Hover.java
new file mode 100644
index 0000000..354437a
--- /dev/null
+++ b/src/jake2/game/M_Hover.java
@@ -0,0 +1,805 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Hover.java,v 1.1 2004-07-07 19:59:15 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Hover extends Game {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_stand01 = 0;
+ public final static int FRAME_stand02 = 1;
+ public final static int FRAME_stand03 = 2;
+ public final static int FRAME_stand04 = 3;
+ public final static int FRAME_stand05 = 4;
+ public final static int FRAME_stand06 = 5;
+ public final static int FRAME_stand07 = 6;
+ public final static int FRAME_stand08 = 7;
+ public final static int FRAME_stand09 = 8;
+ public final static int FRAME_stand10 = 9;
+ public final static int FRAME_stand11 = 10;
+ public final static int FRAME_stand12 = 11;
+ public final static int FRAME_stand13 = 12;
+ public final static int FRAME_stand14 = 13;
+ public final static int FRAME_stand15 = 14;
+ public final static int FRAME_stand16 = 15;
+ public final static int FRAME_stand17 = 16;
+ public final static int FRAME_stand18 = 17;
+ public final static int FRAME_stand19 = 18;
+ public final static int FRAME_stand20 = 19;
+ public final static int FRAME_stand21 = 20;
+ public final static int FRAME_stand22 = 21;
+ public final static int FRAME_stand23 = 22;
+ public final static int FRAME_stand24 = 23;
+ public final static int FRAME_stand25 = 24;
+ public final static int FRAME_stand26 = 25;
+ public final static int FRAME_stand27 = 26;
+ public final static int FRAME_stand28 = 27;
+ public final static int FRAME_stand29 = 28;
+ public final static int FRAME_stand30 = 29;
+ public final static int FRAME_forwrd01 = 30;
+ public final static int FRAME_forwrd02 = 31;
+ public final static int FRAME_forwrd03 = 32;
+ public final static int FRAME_forwrd04 = 33;
+ public final static int FRAME_forwrd05 = 34;
+ public final static int FRAME_forwrd06 = 35;
+ public final static int FRAME_forwrd07 = 36;
+ public final static int FRAME_forwrd08 = 37;
+ public final static int FRAME_forwrd09 = 38;
+ public final static int FRAME_forwrd10 = 39;
+ public final static int FRAME_forwrd11 = 40;
+ public final static int FRAME_forwrd12 = 41;
+ public final static int FRAME_forwrd13 = 42;
+ public final static int FRAME_forwrd14 = 43;
+ public final static int FRAME_forwrd15 = 44;
+ public final static int FRAME_forwrd16 = 45;
+ public final static int FRAME_forwrd17 = 46;
+ public final static int FRAME_forwrd18 = 47;
+ public final static int FRAME_forwrd19 = 48;
+ public final static int FRAME_forwrd20 = 49;
+ public final static int FRAME_forwrd21 = 50;
+ public final static int FRAME_forwrd22 = 51;
+ public final static int FRAME_forwrd23 = 52;
+ public final static int FRAME_forwrd24 = 53;
+ public final static int FRAME_forwrd25 = 54;
+ public final static int FRAME_forwrd26 = 55;
+ public final static int FRAME_forwrd27 = 56;
+ public final static int FRAME_forwrd28 = 57;
+ public final static int FRAME_forwrd29 = 58;
+ public final static int FRAME_forwrd30 = 59;
+ public final static int FRAME_forwrd31 = 60;
+ public final static int FRAME_forwrd32 = 61;
+ public final static int FRAME_forwrd33 = 62;
+ public final static int FRAME_forwrd34 = 63;
+ public final static int FRAME_forwrd35 = 64;
+ public final static int FRAME_stop101 = 65;
+ public final static int FRAME_stop102 = 66;
+ public final static int FRAME_stop103 = 67;
+ public final static int FRAME_stop104 = 68;
+ public final static int FRAME_stop105 = 69;
+ public final static int FRAME_stop106 = 70;
+ public final static int FRAME_stop107 = 71;
+ public final static int FRAME_stop108 = 72;
+ public final static int FRAME_stop109 = 73;
+ public final static int FRAME_stop201 = 74;
+ public final static int FRAME_stop202 = 75;
+ public final static int FRAME_stop203 = 76;
+ public final static int FRAME_stop204 = 77;
+ public final static int FRAME_stop205 = 78;
+ public final static int FRAME_stop206 = 79;
+ public final static int FRAME_stop207 = 80;
+ public final static int FRAME_stop208 = 81;
+ public final static int FRAME_takeof01 = 82;
+ public final static int FRAME_takeof02 = 83;
+ public final static int FRAME_takeof03 = 84;
+ public final static int FRAME_takeof04 = 85;
+ public final static int FRAME_takeof05 = 86;
+ public final static int FRAME_takeof06 = 87;
+ public final static int FRAME_takeof07 = 88;
+ public final static int FRAME_takeof08 = 89;
+ public final static int FRAME_takeof09 = 90;
+ public final static int FRAME_takeof10 = 91;
+ public final static int FRAME_takeof11 = 92;
+ public final static int FRAME_takeof12 = 93;
+ public final static int FRAME_takeof13 = 94;
+ public final static int FRAME_takeof14 = 95;
+ public final static int FRAME_takeof15 = 96;
+ public final static int FRAME_takeof16 = 97;
+ public final static int FRAME_takeof17 = 98;
+ public final static int FRAME_takeof18 = 99;
+ public final static int FRAME_takeof19 = 100;
+ public final static int FRAME_takeof20 = 101;
+ public final static int FRAME_takeof21 = 102;
+ public final static int FRAME_takeof22 = 103;
+ public final static int FRAME_takeof23 = 104;
+ public final static int FRAME_takeof24 = 105;
+ public final static int FRAME_takeof25 = 106;
+ public final static int FRAME_takeof26 = 107;
+ public final static int FRAME_takeof27 = 108;
+ public final static int FRAME_takeof28 = 109;
+ public final static int FRAME_takeof29 = 110;
+ public final static int FRAME_takeof30 = 111;
+ public final static int FRAME_land01 = 112;
+ public final static int FRAME_pain101 = 113;
+ public final static int FRAME_pain102 = 114;
+ public final static int FRAME_pain103 = 115;
+ public final static int FRAME_pain104 = 116;
+ public final static int FRAME_pain105 = 117;
+ public final static int FRAME_pain106 = 118;
+ public final static int FRAME_pain107 = 119;
+ public final static int FRAME_pain108 = 120;
+ public final static int FRAME_pain109 = 121;
+ public final static int FRAME_pain110 = 122;
+ public final static int FRAME_pain111 = 123;
+ public final static int FRAME_pain112 = 124;
+ public final static int FRAME_pain113 = 125;
+ public final static int FRAME_pain114 = 126;
+ public final static int FRAME_pain115 = 127;
+ public final static int FRAME_pain116 = 128;
+ public final static int FRAME_pain117 = 129;
+ public final static int FRAME_pain118 = 130;
+ public final static int FRAME_pain119 = 131;
+ public final static int FRAME_pain120 = 132;
+ public final static int FRAME_pain121 = 133;
+ public final static int FRAME_pain122 = 134;
+ public final static int FRAME_pain123 = 135;
+ public final static int FRAME_pain124 = 136;
+ public final static int FRAME_pain125 = 137;
+ public final static int FRAME_pain126 = 138;
+ public final static int FRAME_pain127 = 139;
+ public final static int FRAME_pain128 = 140;
+ public final static int FRAME_pain201 = 141;
+ public final static int FRAME_pain202 = 142;
+ public final static int FRAME_pain203 = 143;
+ public final static int FRAME_pain204 = 144;
+ public final static int FRAME_pain205 = 145;
+ public final static int FRAME_pain206 = 146;
+ public final static int FRAME_pain207 = 147;
+ public final static int FRAME_pain208 = 148;
+ public final static int FRAME_pain209 = 149;
+ public final static int FRAME_pain210 = 150;
+ public final static int FRAME_pain211 = 151;
+ public final static int FRAME_pain212 = 152;
+ public final static int FRAME_pain301 = 153;
+ public final static int FRAME_pain302 = 154;
+ public final static int FRAME_pain303 = 155;
+ public final static int FRAME_pain304 = 156;
+ public final static int FRAME_pain305 = 157;
+ public final static int FRAME_pain306 = 158;
+ public final static int FRAME_pain307 = 159;
+ public final static int FRAME_pain308 = 160;
+ public final static int FRAME_pain309 = 161;
+ public final static int FRAME_death101 = 162;
+ public final static int FRAME_death102 = 163;
+ public final static int FRAME_death103 = 164;
+ public final static int FRAME_death104 = 165;
+ public final static int FRAME_death105 = 166;
+ public final static int FRAME_death106 = 167;
+ public final static int FRAME_death107 = 168;
+ public final static int FRAME_death108 = 169;
+ public final static int FRAME_death109 = 170;
+ public final static int FRAME_death110 = 171;
+ public final static int FRAME_death111 = 172;
+ public final static int FRAME_backwd01 = 173;
+ public final static int FRAME_backwd02 = 174;
+ public final static int FRAME_backwd03 = 175;
+ public final static int FRAME_backwd04 = 176;
+ public final static int FRAME_backwd05 = 177;
+ public final static int FRAME_backwd06 = 178;
+ public final static int FRAME_backwd07 = 179;
+ public final static int FRAME_backwd08 = 180;
+ public final static int FRAME_backwd09 = 181;
+ public final static int FRAME_backwd10 = 182;
+ public final static int FRAME_backwd11 = 183;
+ public final static int FRAME_backwd12 = 184;
+ public final static int FRAME_backwd13 = 185;
+ public final static int FRAME_backwd14 = 186;
+ public final static int FRAME_backwd15 = 187;
+ public final static int FRAME_backwd16 = 188;
+ public final static int FRAME_backwd17 = 189;
+ public final static int FRAME_backwd18 = 190;
+ public final static int FRAME_backwd19 = 191;
+ public final static int FRAME_backwd20 = 192;
+ public final static int FRAME_backwd21 = 193;
+ public final static int FRAME_backwd22 = 194;
+ public final static int FRAME_backwd23 = 195;
+ public final static int FRAME_backwd24 = 196;
+ public final static int FRAME_attak101 = 197;
+ public final static int FRAME_attak102 = 198;
+ public final static int FRAME_attak103 = 199;
+ public final static int FRAME_attak104 = 200;
+ public final static int FRAME_attak105 = 201;
+ public final static int FRAME_attak106 = 202;
+ public final static int FRAME_attak107 = 203;
+ public final static int FRAME_attak108 = 204;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_death1;
+ static int sound_death2;
+ static int sound_sight;
+ static int sound_search1;
+ static int sound_search2;
+
+
+ static EntThinkAdapter hover_reattack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.enemy.health > 0)
+ if (visible(self, self.enemy))
+ if (Lib.random() <= 0.6) {
+ self.monsterinfo.currentmove = hover_move_attack1;
+ return true;
+ }
+ self.monsterinfo.currentmove = hover_move_end_attack;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_fire_blaster = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] start={0,0,0};
+ float[] forward={0,0,0}, right={0,0,0};
+ float[] end={0,0,0};
+ float[] dir={0,0,0};
+ int effect;
+
+ if (self.s.frame == FRAME_attak104)
+ effect = EF_HYPERBLASTER;
+ else
+ effect = 0;
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[MZ2_HOVER_BLASTER_1], forward, right, start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ end[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(end, start, dir);
+
+ Monster.monster_fire_blaster(self, start, dir, 1, 1000, MZ2_HOVER_BLASTER_1, effect);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = hover_move_stand;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND)!=0)
+ self.monsterinfo.currentmove = hover_move_stand;
+ else
+ self.monsterinfo.currentmove = hover_move_run;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = hover_move_walk;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_start_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = hover_move_start_attack;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = hover_move_attack1;
+ return true;
+ }
+ };
+
+ static EntPainAdapter hover_pain = new EntPainAdapter() {
+ public void hover_pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (damage <= 25) {
+ if (Lib.random() < 0.5) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = hover_move_pain3;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = hover_move_pain2;
+ }
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = hover_move_pain1;
+ }
+ }
+ };
+ static EntThinkAdapter hover_deadthink = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (null==self.groundentity && level.time < self.timestamp) {
+ self.nextthink = level.time + FRAMETIME;
+ return true;
+ }
+ BecomeExplosion1(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ self.think = hover_deadthink;
+ self.nextthink = level.time + FRAMETIME;
+ self.timestamp = level.time + 15;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntDieAdapter hover_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.currentmove = hover_move_death1;
+ }
+ };
+
+ static EntInteractAdapter hover_sight = new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter hover_search = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t hover_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t hover_move_stand = new mmove_t(FRAME_stand01, FRAME_stand30, hover_frames_stand, null);
+
+ static mframe_t hover_frames_stop1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_stop1 = new mmove_t(FRAME_stop101, FRAME_stop109, hover_frames_stop1, null);
+
+ static mframe_t hover_frames_stop2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_stop2 = new mmove_t(FRAME_stop201, FRAME_stop208, hover_frames_stop2, null);
+
+ static mframe_t hover_frames_takeoff[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -9, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_takeoff = new mmove_t(FRAME_takeof01, FRAME_takeof30, hover_frames_takeoff, null);
+
+ static mframe_t hover_frames_pain3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_pain3 = new mmove_t(FRAME_pain301, FRAME_pain309, hover_frames_pain3, hover_run);
+
+ static mframe_t hover_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_pain2 = new mmove_t(FRAME_pain201, FRAME_pain212, hover_frames_pain2, hover_run);
+
+ static mframe_t hover_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, -8, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 7, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 4, null)};
+ static mmove_t hover_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain128, hover_frames_pain1, hover_run);
+
+ static mframe_t hover_frames_land[] = new mframe_t[] { new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_land = new mmove_t(FRAME_land01, FRAME_land01, hover_frames_land, null);
+
+ static mframe_t hover_frames_forward[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_forward = new mmove_t(FRAME_forwrd01, FRAME_forwrd35, hover_frames_forward, null);
+
+ static mframe_t hover_frames_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null)};
+ static mmove_t hover_move_walk = new mmove_t(FRAME_forwrd01, FRAME_forwrd35, hover_frames_walk, null);
+
+ static mframe_t hover_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 10, null)};
+ static mmove_t hover_move_run = new mmove_t(FRAME_forwrd01, FRAME_forwrd35, hover_frames_run, null);
+
+ static mframe_t hover_frames_death1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -10, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 7, null)};
+ static mmove_t hover_move_death1 = new mmove_t(FRAME_death101, FRAME_death111, hover_frames_death1, hover_dead);
+
+ static mframe_t hover_frames_backward[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t hover_move_backward = new mmove_t(FRAME_backwd01, FRAME_backwd24, hover_frames_backward, null);
+
+ static mframe_t hover_frames_start_attack[] =
+ new mframe_t[] { new mframe_t(ai_charge, 1, null), new mframe_t(ai_charge, 1, null), new mframe_t(ai_charge, 1, null)};
+ static mmove_t hover_move_start_attack = new mmove_t(FRAME_attak101, FRAME_attak103, hover_frames_start_attack, hover_attack);
+
+ static mframe_t hover_frames_attack1[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, -10, hover_fire_blaster),
+ new mframe_t(ai_charge, -10, hover_fire_blaster),
+ new mframe_t(ai_charge, 0, hover_reattack),
+ };
+ static mmove_t hover_move_attack1 = new mmove_t(FRAME_attak104, FRAME_attak106, hover_frames_attack1, null);
+
+ static mframe_t hover_frames_end_attack[] = new mframe_t[] { new mframe_t(ai_charge, 1, null), new mframe_t(ai_charge, 1, null)};
+ static mmove_t hover_move_end_attack = new mmove_t(FRAME_attak107, FRAME_attak108, hover_frames_end_attack, hover_run);
+
+ /*QUAKED monster_hover (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_hover(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_pain1 = gi.soundindex("hover/hovpain1.wav");
+ sound_pain2 = gi.soundindex("hover/hovpain2.wav");
+ sound_death1 = gi.soundindex("hover/hovdeth1.wav");
+ sound_death2 = gi.soundindex("hover/hovdeth2.wav");
+ sound_sight = gi.soundindex("hover/hovsght1.wav");
+ sound_search1 = gi.soundindex("hover/hovsrch1.wav");
+ sound_search2 = gi.soundindex("hover/hovsrch2.wav");
+
+ gi.soundindex("hover/hovatck1.wav");
+
+ self.s.sound = gi.soundindex("hover/hovidle1.wav");
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/hover/tris.md2");
+ Math3D.VectorSet(self.mins, -24, -24, -24);
+ Math3D.VectorSet(self.maxs, 24, 24, 32);
+
+ self.health = 240;
+ self.gib_health = -100;
+ self.mass = 150;
+
+ self.pain = hover_pain;
+ self.die = hover_die;
+
+ self.monsterinfo.stand = hover_stand;
+ self.monsterinfo.walk = hover_walk;
+ self.monsterinfo.run = hover_run;
+ // self.monsterinfo.dodge = hover_dodge;
+ self.monsterinfo.attack = hover_start_attack;
+ self.monsterinfo.sight = hover_sight;
+ self.monsterinfo.search = hover_search;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = hover_move_stand;
+ self.monsterinfo.scale = MODEL_SCALE;
+
+ flymonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Infantry.java b/src/jake2/game/M_Infantry.java
new file mode 100644
index 0000000..385af76
--- /dev/null
+++ b/src/jake2/game/M_Infantry.java
@@ -0,0 +1,814 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Infantry.java,v 1.1 2004-07-07 19:59:15 hzi Exp $
+
+package jake2.game;
+
+import jake2.client.M;
+import jake2.util.*;
+
+public class M_Infantry extends Game {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_gun02 = 0;
+ public final static int FRAME_stand01 = 1;
+ public final static int FRAME_stand02 = 2;
+ public final static int FRAME_stand03 = 3;
+ public final static int FRAME_stand04 = 4;
+ public final static int FRAME_stand05 = 5;
+ public final static int FRAME_stand06 = 6;
+ public final static int FRAME_stand07 = 7;
+ public final static int FRAME_stand08 = 8;
+ public final static int FRAME_stand09 = 9;
+ public final static int FRAME_stand10 = 10;
+ public final static int FRAME_stand11 = 11;
+ public final static int FRAME_stand12 = 12;
+ public final static int FRAME_stand13 = 13;
+ public final static int FRAME_stand14 = 14;
+ public final static int FRAME_stand15 = 15;
+ public final static int FRAME_stand16 = 16;
+ public final static int FRAME_stand17 = 17;
+ public final static int FRAME_stand18 = 18;
+ public final static int FRAME_stand19 = 19;
+ public final static int FRAME_stand20 = 20;
+ public final static int FRAME_stand21 = 21;
+ public final static int FRAME_stand22 = 22;
+ public final static int FRAME_stand23 = 23;
+ public final static int FRAME_stand24 = 24;
+ public final static int FRAME_stand25 = 25;
+ public final static int FRAME_stand26 = 26;
+ public final static int FRAME_stand27 = 27;
+ public final static int FRAME_stand28 = 28;
+ public final static int FRAME_stand29 = 29;
+ public final static int FRAME_stand30 = 30;
+ public final static int FRAME_stand31 = 31;
+ public final static int FRAME_stand32 = 32;
+ public final static int FRAME_stand33 = 33;
+ public final static int FRAME_stand34 = 34;
+ public final static int FRAME_stand35 = 35;
+ public final static int FRAME_stand36 = 36;
+ public final static int FRAME_stand37 = 37;
+ public final static int FRAME_stand38 = 38;
+ public final static int FRAME_stand39 = 39;
+ public final static int FRAME_stand40 = 40;
+ public final static int FRAME_stand41 = 41;
+ public final static int FRAME_stand42 = 42;
+ public final static int FRAME_stand43 = 43;
+ public final static int FRAME_stand44 = 44;
+ public final static int FRAME_stand45 = 45;
+ public final static int FRAME_stand46 = 46;
+ public final static int FRAME_stand47 = 47;
+ public final static int FRAME_stand48 = 48;
+ public final static int FRAME_stand49 = 49;
+ public final static int FRAME_stand50 = 50;
+ public final static int FRAME_stand51 = 51;
+ public final static int FRAME_stand52 = 52;
+ public final static int FRAME_stand53 = 53;
+ public final static int FRAME_stand54 = 54;
+ public final static int FRAME_stand55 = 55;
+ public final static int FRAME_stand56 = 56;
+ public final static int FRAME_stand57 = 57;
+ public final static int FRAME_stand58 = 58;
+ public final static int FRAME_stand59 = 59;
+ public final static int FRAME_stand60 = 60;
+ public final static int FRAME_stand61 = 61;
+ public final static int FRAME_stand62 = 62;
+ public final static int FRAME_stand63 = 63;
+ public final static int FRAME_stand64 = 64;
+ public final static int FRAME_stand65 = 65;
+ public final static int FRAME_stand66 = 66;
+ public final static int FRAME_stand67 = 67;
+ public final static int FRAME_stand68 = 68;
+ public final static int FRAME_stand69 = 69;
+ public final static int FRAME_stand70 = 70;
+ public final static int FRAME_stand71 = 71;
+ public final static int FRAME_walk01 = 72;
+ public final static int FRAME_walk02 = 73;
+ public final static int FRAME_walk03 = 74;
+ public final static int FRAME_walk04 = 75;
+ public final static int FRAME_walk05 = 76;
+ public final static int FRAME_walk06 = 77;
+ public final static int FRAME_walk07 = 78;
+ public final static int FRAME_walk08 = 79;
+ public final static int FRAME_walk09 = 80;
+ public final static int FRAME_walk10 = 81;
+ public final static int FRAME_walk11 = 82;
+ public final static int FRAME_walk12 = 83;
+ public final static int FRAME_walk13 = 84;
+ public final static int FRAME_walk14 = 85;
+ public final static int FRAME_walk15 = 86;
+ public final static int FRAME_walk16 = 87;
+ public final static int FRAME_walk17 = 88;
+ public final static int FRAME_walk18 = 89;
+ public final static int FRAME_walk19 = 90;
+ public final static int FRAME_walk20 = 91;
+ public final static int FRAME_run01 = 92;
+ public final static int FRAME_run02 = 93;
+ public final static int FRAME_run03 = 94;
+ public final static int FRAME_run04 = 95;
+ public final static int FRAME_run05 = 96;
+ public final static int FRAME_run06 = 97;
+ public final static int FRAME_run07 = 98;
+ public final static int FRAME_run08 = 99;
+ public final static int FRAME_pain101 = 100;
+ public final static int FRAME_pain102 = 101;
+ public final static int FRAME_pain103 = 102;
+ public final static int FRAME_pain104 = 103;
+ public final static int FRAME_pain105 = 104;
+ public final static int FRAME_pain106 = 105;
+ public final static int FRAME_pain107 = 106;
+ public final static int FRAME_pain108 = 107;
+ public final static int FRAME_pain109 = 108;
+ public final static int FRAME_pain110 = 109;
+ public final static int FRAME_pain201 = 110;
+ public final static int FRAME_pain202 = 111;
+ public final static int FRAME_pain203 = 112;
+ public final static int FRAME_pain204 = 113;
+ public final static int FRAME_pain205 = 114;
+ public final static int FRAME_pain206 = 115;
+ public final static int FRAME_pain207 = 116;
+ public final static int FRAME_pain208 = 117;
+ public final static int FRAME_pain209 = 118;
+ public final static int FRAME_pain210 = 119;
+ public final static int FRAME_duck01 = 120;
+ public final static int FRAME_duck02 = 121;
+ public final static int FRAME_duck03 = 122;
+ public final static int FRAME_duck04 = 123;
+ public final static int FRAME_duck05 = 124;
+ public final static int FRAME_death101 = 125;
+ public final static int FRAME_death102 = 126;
+ public final static int FRAME_death103 = 127;
+ public final static int FRAME_death104 = 128;
+ public final static int FRAME_death105 = 129;
+ public final static int FRAME_death106 = 130;
+ public final static int FRAME_death107 = 131;
+ public final static int FRAME_death108 = 132;
+ public final static int FRAME_death109 = 133;
+ public final static int FRAME_death110 = 134;
+ public final static int FRAME_death111 = 135;
+ public final static int FRAME_death112 = 136;
+ public final static int FRAME_death113 = 137;
+ public final static int FRAME_death114 = 138;
+ public final static int FRAME_death115 = 139;
+ public final static int FRAME_death116 = 140;
+ public final static int FRAME_death117 = 141;
+ public final static int FRAME_death118 = 142;
+ public final static int FRAME_death119 = 143;
+ public final static int FRAME_death120 = 144;
+ public final static int FRAME_death201 = 145;
+ public final static int FRAME_death202 = 146;
+ public final static int FRAME_death203 = 147;
+ public final static int FRAME_death204 = 148;
+ public final static int FRAME_death205 = 149;
+ public final static int FRAME_death206 = 150;
+ public final static int FRAME_death207 = 151;
+ public final static int FRAME_death208 = 152;
+ public final static int FRAME_death209 = 153;
+ public final static int FRAME_death210 = 154;
+ public final static int FRAME_death211 = 155;
+ public final static int FRAME_death212 = 156;
+ public final static int FRAME_death213 = 157;
+ public final static int FRAME_death214 = 158;
+ public final static int FRAME_death215 = 159;
+ public final static int FRAME_death216 = 160;
+ public final static int FRAME_death217 = 161;
+ public final static int FRAME_death218 = 162;
+ public final static int FRAME_death219 = 163;
+ public final static int FRAME_death220 = 164;
+ public final static int FRAME_death221 = 165;
+ public final static int FRAME_death222 = 166;
+ public final static int FRAME_death223 = 167;
+ public final static int FRAME_death224 = 168;
+ public final static int FRAME_death225 = 169;
+ public final static int FRAME_death301 = 170;
+ public final static int FRAME_death302 = 171;
+ public final static int FRAME_death303 = 172;
+ public final static int FRAME_death304 = 173;
+ public final static int FRAME_death305 = 174;
+ public final static int FRAME_death306 = 175;
+ public final static int FRAME_death307 = 176;
+ public final static int FRAME_death308 = 177;
+ public final static int FRAME_death309 = 178;
+ public final static int FRAME_block01 = 179;
+ public final static int FRAME_block02 = 180;
+ public final static int FRAME_block03 = 181;
+ public final static int FRAME_block04 = 182;
+ public final static int FRAME_block05 = 183;
+ public final static int FRAME_attak101 = 184;
+ public final static int FRAME_attak102 = 185;
+ public final static int FRAME_attak103 = 186;
+ public final static int FRAME_attak104 = 187;
+ public final static int FRAME_attak105 = 188;
+ public final static int FRAME_attak106 = 189;
+ public final static int FRAME_attak107 = 190;
+ public final static int FRAME_attak108 = 191;
+ public final static int FRAME_attak109 = 192;
+ public final static int FRAME_attak110 = 193;
+ public final static int FRAME_attak111 = 194;
+ public final static int FRAME_attak112 = 195;
+ public final static int FRAME_attak113 = 196;
+ public final static int FRAME_attak114 = 197;
+ public final static int FRAME_attak115 = 198;
+ public final static int FRAME_attak201 = 199;
+ public final static int FRAME_attak202 = 200;
+ public final static int FRAME_attak203 = 201;
+ public final static int FRAME_attak204 = 202;
+ public final static int FRAME_attak205 = 203;
+ public final static int FRAME_attak206 = 204;
+ public final static int FRAME_attak207 = 205;
+ public final static int FRAME_attak208 = 206;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_die1;
+ static int sound_die2;
+
+ static int sound_gunshot;
+ static int sound_weapon_cock;
+ static int sound_punch_swing;
+ static int sound_punch_hit;
+ static int sound_sight;
+ static int sound_search;
+ static int sound_idle;
+
+ static mframe_t infantry_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t infantry_move_stand = new mmove_t(FRAME_stand50, FRAME_stand71, infantry_frames_stand, null);
+
+ static EntThinkAdapter infantry_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = infantry_move_stand;
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_fidget[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 3, null),
+ new mframe_t(ai_stand, 6, null),
+ new mframe_t(ai_stand, 3, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -2, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, -1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -1, null),
+ new mframe_t(ai_stand, -1, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, -3, null),
+ new mframe_t(ai_stand, -2, null),
+ new mframe_t(ai_stand, -3, null),
+ new mframe_t(ai_stand, -3, null),
+ new mframe_t(ai_stand, -2, null)};
+ static mmove_t infantry_move_fidget = new mmove_t(FRAME_stand01, FRAME_stand49, infantry_frames_fidget, infantry_stand);
+
+ static EntThinkAdapter infantry_fidget = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = infantry_move_fidget;
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 5, null)};
+ static mmove_t infantry_move_walk = new mmove_t(FRAME_walk03, FRAME_walk14, infantry_frames_walk, null);
+
+ static EntThinkAdapter infantry_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = infantry_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 20, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 7, null),
+ new mframe_t(ai_run, 30, null),
+ new mframe_t(ai_run, 35, null),
+ new mframe_t(ai_run, 2, null),
+ new mframe_t(ai_run, 6, null)};
+ static mmove_t infantry_move_run = new mmove_t(FRAME_run01, FRAME_run08, infantry_frames_run, null);
+
+ static EntThinkAdapter infantry_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove = infantry_move_stand;
+ else
+ self.monsterinfo.currentmove = infantry_move_run;
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 2, null)};
+ static mmove_t infantry_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain110, infantry_frames_pain1, infantry_run);
+
+ static mframe_t infantry_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, 2, null)};
+ static mmove_t infantry_move_pain2 = new mmove_t(FRAME_pain201, FRAME_pain210, infantry_frames_pain2, infantry_run);
+
+ static EntPainAdapter infantry_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+
+ int n;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ n = Lib.rand() % 2;
+ if (n == 0) {
+ self.monsterinfo.currentmove = infantry_move_pain1;
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ } else {
+ self.monsterinfo.currentmove = infantry_move_pain2;
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ }
+ }
+ };
+
+ static float[] aimangles[] = { { 0.0f, 5.0f, 0.0f }, {
+ 10.0f, 15.0f, 0.0f }, {
+ 20.0f, 25.0f, 0.0f }, {
+ 25.0f, 35.0f, 0.0f }, {
+ 30.0f, 40.0f, 0.0f }, {
+ 30.0f, 45.0f, 0.0f }, {
+ 25.0f, 50.0f, 0.0f }, {
+ 20.0f, 40.0f, 0.0f }, {
+ 15.0f, 35.0f, 0.0f }, {
+ 40.0f, 35.0f, 0.0f }, {
+ 70.0f, 35.0f, 0.0f }, {
+ 90.0f, 35.0f, 0.0f }
+ };
+ static EntThinkAdapter InfantryMachineGun = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] start={0,0,0}, target={0,0,0};
+ float[] forward={0,0,0}, right={0,0,0};
+ float[] vec={0,0,0};
+ int flash_number;
+
+ if (self.s.frame == FRAME_attak111) {
+ flash_number = MZ2_INFANTRY_MACHINEGUN_1;
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ if (self.enemy != null) {
+ Math3D.VectorMA(self.enemy.s.origin, -0.2f, self.enemy.velocity, target);
+ target[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(target, start, forward);
+ Math3D.VectorNormalize(forward);
+ } else {
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ }
+ } else {
+ flash_number = MZ2_INFANTRY_MACHINEGUN_2 + (self.s.frame - FRAME_death211);
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ Math3D.VectorSubtract(self.s.angles, aimangles[flash_number - MZ2_INFANTRY_MACHINEGUN_2], vec);
+ Math3D.AngleVectors(vec, forward, null, null);
+ }
+
+ Monster.monster_fire_bullet(self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+ return true;
+ }
+ };
+
+ static EntInteractAdapter infantry_sight = new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_BODY, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+ ///
+
+ static EntThinkAdapter infantry_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ gi.linkentity(self);
+
+ M.M_FlyCheck.think(self);
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_death1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 9, null),
+ new mframe_t(ai_move, 9, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -3, null)};
+ static mmove_t infantry_move_death1 = new mmove_t(FRAME_death101, FRAME_death120, infantry_frames_death1, infantry_dead);
+
+ // Off with his head
+ static mframe_t infantry_frames_death2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, InfantryMachineGun),
+ new mframe_t(ai_move, -2, InfantryMachineGun),
+ new mframe_t(ai_move, -3, InfantryMachineGun),
+ new mframe_t(ai_move, -1, InfantryMachineGun),
+ new mframe_t(ai_move, -2, InfantryMachineGun),
+ new mframe_t(ai_move, 0, InfantryMachineGun),
+ new mframe_t(ai_move, 2, InfantryMachineGun),
+ new mframe_t(ai_move, 2, InfantryMachineGun),
+ new mframe_t(ai_move, 3, InfantryMachineGun),
+ new mframe_t(ai_move, -10, InfantryMachineGun),
+ new mframe_t(ai_move, -7, InfantryMachineGun),
+ new mframe_t(ai_move, -8, InfantryMachineGun),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t infantry_move_death2 = new mmove_t(FRAME_death201, FRAME_death225, infantry_frames_death2, infantry_dead);
+
+ static mframe_t infantry_frames_death3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -11, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -11, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t infantry_move_death3 = new mmove_t(FRAME_death301, FRAME_death309, infantry_frames_death3, infantry_dead);
+
+ static EntDieAdapter infantry_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+
+ n = Lib.rand() % 3;
+ if (n == 0) {
+ self.monsterinfo.currentmove = infantry_move_death1;
+ gi.sound(self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
+ } else if (n == 1) {
+ self.monsterinfo.currentmove = infantry_move_death2;
+ gi.sound(self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0);
+ } else {
+ self.monsterinfo.currentmove = infantry_move_death3;
+ gi.sound(self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
+ }
+ }
+ };
+
+ static EntThinkAdapter infantry_duck_down = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_DUCKED) != 0)
+ return true;
+ self.monsterinfo.aiflags |= AI_DUCKED;
+ self.maxs[2] -= 32;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.pausetime = level.time + 1;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter infantry_duck_hold = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter infantry_duck_up = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.aiflags &= ~AI_DUCKED;
+ self.maxs[2] += 32;
+ self.takedamage = DAMAGE_AIM;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_duck[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -2, infantry_duck_down),
+ new mframe_t(ai_move, -5, infantry_duck_hold),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 4, infantry_duck_up),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t infantry_move_duck = new mmove_t(FRAME_duck01, FRAME_duck05, infantry_frames_duck, infantry_run);
+
+ static EntDodgeAdapter infantry_dodge = new EntDodgeAdapter() {
+ public void dodge(edict_t self, edict_t attacker, float eta) {
+ if (Lib.random() > 0.25)
+ return;
+
+ if (null == self.enemy)
+ self.enemy = attacker;
+
+ self.monsterinfo.currentmove = infantry_move_duck;
+ }
+ };
+
+ static EntThinkAdapter infantry_cock_gun = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ int n;
+
+ gi.sound(self, CHAN_WEAPON, sound_weapon_cock, 1, ATTN_NORM, 0);
+ n = (Lib.rand() & 15) + 3 + 7;
+ self.monsterinfo.pausetime = level.time + n * FRAMETIME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter infantry_fire = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ InfantryMachineGun.think(self);
+
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_attack1[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, 0, infantry_cock_gun),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 1, infantry_fire),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, -3, null)};
+ static mmove_t infantry_move_attack1 = new mmove_t(FRAME_attak101, FRAME_attak115, infantry_frames_attack1, infantry_run);
+
+ static EntThinkAdapter infantry_swing = new EntThinkAdapter() {
+
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_punch_swing, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter infantry_smack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim = { 0, 0, 0 };
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, 0, 0);
+ if (Fire.fire_hit(self, aim, (5 + (Lib.rand() % 5)), 50))
+ gi.sound(self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t infantry_frames_attack2[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 6, null),
+ new mframe_t(ai_charge, 0, infantry_swing),
+ new mframe_t(ai_charge, 8, null),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, 8, infantry_smack),
+ new mframe_t(ai_charge, 6, null),
+ new mframe_t(ai_charge, 3, null),
+ };
+ static mmove_t infantry_move_attack2 = new mmove_t(FRAME_attak201, FRAME_attak208, infantry_frames_attack2, infantry_run);
+
+ static EntThinkAdapter infantry_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (range(self, self.enemy) == RANGE_MELEE)
+ self.monsterinfo.currentmove = infantry_move_attack2;
+ else
+ self.monsterinfo.currentmove = infantry_move_attack1;
+ return true;
+ }
+ };
+
+ /*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_infantry(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_pain1 = gi.soundindex("infantry/infpain1.wav");
+ sound_pain2 = gi.soundindex("infantry/infpain2.wav");
+ sound_die1 = gi.soundindex("infantry/infdeth1.wav");
+ sound_die2 = gi.soundindex("infantry/infdeth2.wav");
+
+ sound_gunshot = gi.soundindex("infantry/infatck1.wav");
+ sound_weapon_cock = gi.soundindex("infantry/infatck3.wav");
+ sound_punch_swing = gi.soundindex("infantry/infatck2.wav");
+ sound_punch_hit = gi.soundindex("infantry/melee2.wav");
+
+ sound_sight = gi.soundindex("infantry/infsght1.wav");
+ sound_search = gi.soundindex("infantry/infsrch1.wav");
+ sound_idle = gi.soundindex("infantry/infidle1.wav");
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+
+ self.health = 100;
+ self.gib_health = -40;
+ self.mass = 200;
+
+ self.pain = infantry_pain;
+ self.die = infantry_die;
+
+ self.monsterinfo.stand = infantry_stand;
+ self.monsterinfo.walk = infantry_walk;
+ self.monsterinfo.run = infantry_run;
+ self.monsterinfo.dodge = infantry_dodge;
+ self.monsterinfo.attack = infantry_attack;
+ self.monsterinfo.melee = null;
+ self.monsterinfo.sight = infantry_sight;
+ self.monsterinfo.idle = infantry_fidget;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = infantry_move_stand;
+ self.monsterinfo.scale = MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Insane.java b/src/jake2/game/M_Insane.java
new file mode 100644
index 0000000..a11e990
--- /dev/null
+++ b/src/jake2/game/M_Insane.java
@@ -0,0 +1,959 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Insane.java,v 1.1 2004-07-07 19:59:16 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Insane extends Game {
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_stand1 = 0;
+ public final static int FRAME_stand2 = 1;
+ public final static int FRAME_stand3 = 2;
+ public final static int FRAME_stand4 = 3;
+ public final static int FRAME_stand5 = 4;
+ public final static int FRAME_stand6 = 5;
+ public final static int FRAME_stand7 = 6;
+ public final static int FRAME_stand8 = 7;
+ public final static int FRAME_stand9 = 8;
+ public final static int FRAME_stand10 = 9;
+ public final static int FRAME_stand11 = 10;
+ public final static int FRAME_stand12 = 11;
+ public final static int FRAME_stand13 = 12;
+ public final static int FRAME_stand14 = 13;
+ public final static int FRAME_stand15 = 14;
+ public final static int FRAME_stand16 = 15;
+ public final static int FRAME_stand17 = 16;
+ public final static int FRAME_stand18 = 17;
+ public final static int FRAME_stand19 = 18;
+ public final static int FRAME_stand20 = 19;
+ public final static int FRAME_stand21 = 20;
+ public final static int FRAME_stand22 = 21;
+ public final static int FRAME_stand23 = 22;
+ public final static int FRAME_stand24 = 23;
+ public final static int FRAME_stand25 = 24;
+ public final static int FRAME_stand26 = 25;
+ public final static int FRAME_stand27 = 26;
+ public final static int FRAME_stand28 = 27;
+ public final static int FRAME_stand29 = 28;
+ public final static int FRAME_stand30 = 29;
+ public final static int FRAME_stand31 = 30;
+ public final static int FRAME_stand32 = 31;
+ public final static int FRAME_stand33 = 32;
+ public final static int FRAME_stand34 = 33;
+ public final static int FRAME_stand35 = 34;
+ public final static int FRAME_stand36 = 35;
+ public final static int FRAME_stand37 = 36;
+ public final static int FRAME_stand38 = 37;
+ public final static int FRAME_stand39 = 38;
+ public final static int FRAME_stand40 = 39;
+ public final static int FRAME_stand41 = 40;
+ public final static int FRAME_stand42 = 41;
+ public final static int FRAME_stand43 = 42;
+ public final static int FRAME_stand44 = 43;
+ public final static int FRAME_stand45 = 44;
+ public final static int FRAME_stand46 = 45;
+ public final static int FRAME_stand47 = 46;
+ public final static int FRAME_stand48 = 47;
+ public final static int FRAME_stand49 = 48;
+ public final static int FRAME_stand50 = 49;
+ public final static int FRAME_stand51 = 50;
+ public final static int FRAME_stand52 = 51;
+ public final static int FRAME_stand53 = 52;
+ public final static int FRAME_stand54 = 53;
+ public final static int FRAME_stand55 = 54;
+ public final static int FRAME_stand56 = 55;
+ public final static int FRAME_stand57 = 56;
+ public final static int FRAME_stand58 = 57;
+ public final static int FRAME_stand59 = 58;
+ public final static int FRAME_stand60 = 59;
+ public final static int FRAME_stand61 = 60;
+ public final static int FRAME_stand62 = 61;
+ public final static int FRAME_stand63 = 62;
+ public final static int FRAME_stand64 = 63;
+ public final static int FRAME_stand65 = 64;
+ public final static int FRAME_stand66 = 65;
+ public final static int FRAME_stand67 = 66;
+ public final static int FRAME_stand68 = 67;
+ public final static int FRAME_stand69 = 68;
+ public final static int FRAME_stand70 = 69;
+ public final static int FRAME_stand71 = 70;
+ public final static int FRAME_stand72 = 71;
+ public final static int FRAME_stand73 = 72;
+ public final static int FRAME_stand74 = 73;
+ public final static int FRAME_stand75 = 74;
+ public final static int FRAME_stand76 = 75;
+ public final static int FRAME_stand77 = 76;
+ public final static int FRAME_stand78 = 77;
+ public final static int FRAME_stand79 = 78;
+ public final static int FRAME_stand80 = 79;
+ public final static int FRAME_stand81 = 80;
+ public final static int FRAME_stand82 = 81;
+ public final static int FRAME_stand83 = 82;
+ public final static int FRAME_stand84 = 83;
+ public final static int FRAME_stand85 = 84;
+ public final static int FRAME_stand86 = 85;
+ public final static int FRAME_stand87 = 86;
+ public final static int FRAME_stand88 = 87;
+ public final static int FRAME_stand89 = 88;
+ public final static int FRAME_stand90 = 89;
+ public final static int FRAME_stand91 = 90;
+ public final static int FRAME_stand92 = 91;
+ public final static int FRAME_stand93 = 92;
+ public final static int FRAME_stand94 = 93;
+ public final static int FRAME_stand95 = 94;
+ public final static int FRAME_stand96 = 95;
+ public final static int FRAME_stand97 = 96;
+ public final static int FRAME_stand98 = 97;
+ public final static int FRAME_stand99 = 98;
+ public final static int FRAME_stand100 = 99;
+ public final static int FRAME_stand101 = 100;
+ public final static int FRAME_stand102 = 101;
+ public final static int FRAME_stand103 = 102;
+ public final static int FRAME_stand104 = 103;
+ public final static int FRAME_stand105 = 104;
+ public final static int FRAME_stand106 = 105;
+ public final static int FRAME_stand107 = 106;
+ public final static int FRAME_stand108 = 107;
+ public final static int FRAME_stand109 = 108;
+ public final static int FRAME_stand110 = 109;
+ public final static int FRAME_stand111 = 110;
+ public final static int FRAME_stand112 = 111;
+ public final static int FRAME_stand113 = 112;
+ public final static int FRAME_stand114 = 113;
+ public final static int FRAME_stand115 = 114;
+ public final static int FRAME_stand116 = 115;
+ public final static int FRAME_stand117 = 116;
+ public final static int FRAME_stand118 = 117;
+ public final static int FRAME_stand119 = 118;
+ public final static int FRAME_stand120 = 119;
+ public final static int FRAME_stand121 = 120;
+ public final static int FRAME_stand122 = 121;
+ public final static int FRAME_stand123 = 122;
+ public final static int FRAME_stand124 = 123;
+ public final static int FRAME_stand125 = 124;
+ public final static int FRAME_stand126 = 125;
+ public final static int FRAME_stand127 = 126;
+ public final static int FRAME_stand128 = 127;
+ public final static int FRAME_stand129 = 128;
+ public final static int FRAME_stand130 = 129;
+ public final static int FRAME_stand131 = 130;
+ public final static int FRAME_stand132 = 131;
+ public final static int FRAME_stand133 = 132;
+ public final static int FRAME_stand134 = 133;
+ public final static int FRAME_stand135 = 134;
+ public final static int FRAME_stand136 = 135;
+ public final static int FRAME_stand137 = 136;
+ public final static int FRAME_stand138 = 137;
+ public final static int FRAME_stand139 = 138;
+ public final static int FRAME_stand140 = 139;
+ public final static int FRAME_stand141 = 140;
+ public final static int FRAME_stand142 = 141;
+ public final static int FRAME_stand143 = 142;
+ public final static int FRAME_stand144 = 143;
+ public final static int FRAME_stand145 = 144;
+ public final static int FRAME_stand146 = 145;
+ public final static int FRAME_stand147 = 146;
+ public final static int FRAME_stand148 = 147;
+ public final static int FRAME_stand149 = 148;
+ public final static int FRAME_stand150 = 149;
+ public final static int FRAME_stand151 = 150;
+ public final static int FRAME_stand152 = 151;
+ public final static int FRAME_stand153 = 152;
+ public final static int FRAME_stand154 = 153;
+ public final static int FRAME_stand155 = 154;
+ public final static int FRAME_stand156 = 155;
+ public final static int FRAME_stand157 = 156;
+ public final static int FRAME_stand158 = 157;
+ public final static int FRAME_stand159 = 158;
+ public final static int FRAME_stand160 = 159;
+ public final static int FRAME_walk27 = 160;
+ public final static int FRAME_walk28 = 161;
+ public final static int FRAME_walk29 = 162;
+ public final static int FRAME_walk30 = 163;
+ public final static int FRAME_walk31 = 164;
+ public final static int FRAME_walk32 = 165;
+ public final static int FRAME_walk33 = 166;
+ public final static int FRAME_walk34 = 167;
+ public final static int FRAME_walk35 = 168;
+ public final static int FRAME_walk36 = 169;
+ public final static int FRAME_walk37 = 170;
+ public final static int FRAME_walk38 = 171;
+ public final static int FRAME_walk39 = 172;
+ public final static int FRAME_walk1 = 173;
+ public final static int FRAME_walk2 = 174;
+ public final static int FRAME_walk3 = 175;
+ public final static int FRAME_walk4 = 176;
+ public final static int FRAME_walk5 = 177;
+ public final static int FRAME_walk6 = 178;
+ public final static int FRAME_walk7 = 179;
+ public final static int FRAME_walk8 = 180;
+ public final static int FRAME_walk9 = 181;
+ public final static int FRAME_walk10 = 182;
+ public final static int FRAME_walk11 = 183;
+ public final static int FRAME_walk12 = 184;
+ public final static int FRAME_walk13 = 185;
+ public final static int FRAME_walk14 = 186;
+ public final static int FRAME_walk15 = 187;
+ public final static int FRAME_walk16 = 188;
+ public final static int FRAME_walk17 = 189;
+ public final static int FRAME_walk18 = 190;
+ public final static int FRAME_walk19 = 191;
+ public final static int FRAME_walk20 = 192;
+ public final static int FRAME_walk21 = 193;
+ public final static int FRAME_walk22 = 194;
+ public final static int FRAME_walk23 = 195;
+ public final static int FRAME_walk24 = 196;
+ public final static int FRAME_walk25 = 197;
+ public final static int FRAME_walk26 = 198;
+ public final static int FRAME_st_pain2 = 199;
+ public final static int FRAME_st_pain3 = 200;
+ public final static int FRAME_st_pain4 = 201;
+ public final static int FRAME_st_pain5 = 202;
+ public final static int FRAME_st_pain6 = 203;
+ public final static int FRAME_st_pain7 = 204;
+ public final static int FRAME_st_pain8 = 205;
+ public final static int FRAME_st_pain9 = 206;
+ public final static int FRAME_st_pain10 = 207;
+ public final static int FRAME_st_pain11 = 208;
+ public final static int FRAME_st_pain12 = 209;
+ public final static int FRAME_st_death2 = 210;
+ public final static int FRAME_st_death3 = 211;
+ public final static int FRAME_st_death4 = 212;
+ public final static int FRAME_st_death5 = 213;
+ public final static int FRAME_st_death6 = 214;
+ public final static int FRAME_st_death7 = 215;
+ public final static int FRAME_st_death8 = 216;
+ public final static int FRAME_st_death9 = 217;
+ public final static int FRAME_st_death10 = 218;
+ public final static int FRAME_st_death11 = 219;
+ public final static int FRAME_st_death12 = 220;
+ public final static int FRAME_st_death13 = 221;
+ public final static int FRAME_st_death14 = 222;
+ public final static int FRAME_st_death15 = 223;
+ public final static int FRAME_st_death16 = 224;
+ public final static int FRAME_st_death17 = 225;
+ public final static int FRAME_st_death18 = 226;
+ public final static int FRAME_crawl1 = 227;
+ public final static int FRAME_crawl2 = 228;
+ public final static int FRAME_crawl3 = 229;
+ public final static int FRAME_crawl4 = 230;
+ public final static int FRAME_crawl5 = 231;
+ public final static int FRAME_crawl6 = 232;
+ public final static int FRAME_crawl7 = 233;
+ public final static int FRAME_crawl8 = 234;
+ public final static int FRAME_crawl9 = 235;
+ public final static int FRAME_cr_pain2 = 236;
+ public final static int FRAME_cr_pain3 = 237;
+ public final static int FRAME_cr_pain4 = 238;
+ public final static int FRAME_cr_pain5 = 239;
+ public final static int FRAME_cr_pain6 = 240;
+ public final static int FRAME_cr_pain7 = 241;
+ public final static int FRAME_cr_pain8 = 242;
+ public final static int FRAME_cr_pain9 = 243;
+ public final static int FRAME_cr_pain10 = 244;
+ public final static int FRAME_cr_death10 = 245;
+ public final static int FRAME_cr_death11 = 246;
+ public final static int FRAME_cr_death12 = 247;
+ public final static int FRAME_cr_death13 = 248;
+ public final static int FRAME_cr_death14 = 249;
+ public final static int FRAME_cr_death15 = 250;
+ public final static int FRAME_cr_death16 = 251;
+ public final static int FRAME_cross1 = 252;
+ public final static int FRAME_cross2 = 253;
+ public final static int FRAME_cross3 = 254;
+ public final static int FRAME_cross4 = 255;
+ public final static int FRAME_cross5 = 256;
+ public final static int FRAME_cross6 = 257;
+ public final static int FRAME_cross7 = 258;
+ public final static int FRAME_cross8 = 259;
+ public final static int FRAME_cross9 = 260;
+ public final static int FRAME_cross10 = 261;
+ public final static int FRAME_cross11 = 262;
+ public final static int FRAME_cross12 = 263;
+ public final static int FRAME_cross13 = 264;
+ public final static int FRAME_cross14 = 265;
+ public final static int FRAME_cross15 = 266;
+ public final static int FRAME_cross16 = 267;
+ public final static int FRAME_cross17 = 268;
+ public final static int FRAME_cross18 = 269;
+ public final static int FRAME_cross19 = 270;
+ public final static int FRAME_cross20 = 271;
+ public final static int FRAME_cross21 = 272;
+ public final static int FRAME_cross22 = 273;
+ public final static int FRAME_cross23 = 274;
+ public final static int FRAME_cross24 = 275;
+ public final static int FRAME_cross25 = 276;
+ public final static int FRAME_cross26 = 277;
+ public final static int FRAME_cross27 = 278;
+ public final static int FRAME_cross28 = 279;
+ public final static int FRAME_cross29 = 280;
+ public final static int FRAME_cross30 = 281;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_fist;
+ static int sound_shake;
+ static int sound_moan;
+ static int sound_scream[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ static EntThinkAdapter insane_fist = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_fist, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_shake = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_shake, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_moan = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_moan, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_scream = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_scream[Lib.rand() % 8], 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_cross = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() < 0.8)
+ self.monsterinfo.currentmove = insane_move_cross;
+ else
+ self.monsterinfo.currentmove = insane_move_struggle_cross;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.spawnflags & 16) != 0) // Hold Ground?
+ if (self.s.frame == FRAME_cr_pain10) {
+ self.monsterinfo.currentmove = insane_move_down;
+ return true;
+ }
+ if ((self.spawnflags & 4) != 0)
+ self.monsterinfo.currentmove = insane_move_crawl;
+ else if (Lib.random() <= 0.5)
+ self.monsterinfo.currentmove = insane_move_walk_normal;
+ else
+ self.monsterinfo.currentmove = insane_move_walk_insane;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.spawnflags & 16) != 0) // Hold Ground?
+ if (self.s.frame == FRAME_cr_pain10) {
+ self.monsterinfo.currentmove = insane_move_down;
+ return true;
+ }
+ if ((self.spawnflags & 4) != 0) // Crawling?
+ self.monsterinfo.currentmove = insane_move_runcrawl;
+ else if (Lib.random() <= 0.5) // Else, mix it up
+ self.monsterinfo.currentmove = insane_move_run_normal;
+ else
+ self.monsterinfo.currentmove = insane_move_run_insane;
+ return true;
+ }
+ };
+
+ static EntPainAdapter insane_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ int l, r;
+
+ // if (self.health < (self.max_health / 2))
+ // self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ r = 1 + (Lib.rand() & 1);
+ if (self.health < 25)
+ l = 25;
+ else if (self.health < 50)
+ l = 50;
+ else if (self.health < 75)
+ l = 75;
+ else
+ l = 100;
+ gi.sound(self, CHAN_VOICE, gi.soundindex("player/male/pain" + l + "_" + r + ".wav"), 1, ATTN_IDLE, 0);
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ // Don't go into pain frames if crucified.
+ if ((self.spawnflags & 8) != 0) {
+ self.monsterinfo.currentmove = insane_move_struggle_cross;
+ return;
+ }
+
+ if (((self.s.frame >= FRAME_crawl1) && (self.s.frame <= FRAME_crawl9))
+ || ((self.s.frame >= FRAME_stand99) && (self.s.frame <= FRAME_stand160))) {
+ self.monsterinfo.currentmove = insane_move_crawl_pain;
+ } else
+ self.monsterinfo.currentmove = insane_move_stand_pain;
+ }
+ };
+
+ static EntThinkAdapter insane_onground = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = insane_move_down;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_checkdown = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ // if ( (self.s.frame == FRAME_stand94) || (self.s.frame == FRAME_stand65) )
+ if ((self.spawnflags & 32) != 0) // Always stand
+ return true;
+ if (Lib.random() < 0.3)
+ if (Lib.random() < 0.5)
+ self.monsterinfo.currentmove = insane_move_uptodown;
+ else
+ self.monsterinfo.currentmove = insane_move_jumpdown;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_checkup = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ // If Hold_Ground and Crawl are set
+ if ((self.spawnflags & 4) != 0 && (self.spawnflags & 16) != 0)
+ return true;
+ if (Lib.random() < 0.5)
+ self.monsterinfo.currentmove = insane_move_downtoup;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.spawnflags & 8) != 0) // If crucified
+ {
+ self.monsterinfo.currentmove = insane_move_cross;
+ self.monsterinfo.aiflags |= AI_STAND_GROUND;
+ }
+ // If Hold_Ground and Crawl are set
+ else if ((self.spawnflags & 4) != 0 && (self.spawnflags & 16) != 0)
+ self.monsterinfo.currentmove = insane_move_down;
+ else if (Lib.random() < 0.5)
+ self.monsterinfo.currentmove = insane_move_stand_normal;
+ else
+ self.monsterinfo.currentmove = insane_move_stand_insane;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter insane_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.spawnflags & 8) != 0) {
+ self.flags |= FL_FLY;
+ } else {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ }
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink = 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntDieAdapter insane_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_IDLE, 0);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ gi.sound(self, CHAN_VOICE, gi.soundindex("player/male/death" + ((Lib.rand() % 4) + 1) + ".wav"), 1, ATTN_IDLE, 0);
+
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+
+ if ((self.spawnflags & 8) != 0) {
+ insane_dead.think(self);
+ } else {
+ if (((self.s.frame >= FRAME_crawl1) && (self.s.frame <= FRAME_crawl9))
+ || ((self.s.frame >= FRAME_stand99) && (self.s.frame <= FRAME_stand160)))
+ self.monsterinfo.currentmove = insane_move_crawl_death;
+ else
+ self.monsterinfo.currentmove = insane_move_stand_death;
+ }
+ }
+
+ };
+
+ static mframe_t insane_frames_stand_normal[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, insane_checkdown)};
+
+ static mmove_t insane_move_stand_normal = new mmove_t(FRAME_stand60, FRAME_stand65, insane_frames_stand_normal, insane_stand);
+
+ static mframe_t insane_frames_stand_insane[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, insane_shake),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, insane_checkdown)};
+ static mmove_t insane_move_stand_insane = new mmove_t(FRAME_stand65, FRAME_stand94, insane_frames_stand_insane, insane_stand);
+
+ static mframe_t insane_frames_uptodown[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, insane_moan),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2.7f, null),
+ new mframe_t(ai_move, 4.1f, null),
+ new mframe_t(ai_move, 6f, null),
+ new mframe_t(ai_move, 7.6f, null),
+ new mframe_t(ai_move, 3.6f, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, insane_fist),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, insane_fist),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_uptodown = new mmove_t(FRAME_stand1, FRAME_stand40, insane_frames_uptodown, insane_onground);
+
+ static mframe_t insane_frames_downtoup[] = new mframe_t[] { new mframe_t(ai_move, -0.7f, null), // 41
+ new mframe_t(ai_move, -1.2f, null), // 42
+ new mframe_t(ai_move, -1.5f, null), // 43
+ new mframe_t(ai_move, -4.5f, null), // 44
+ new mframe_t(ai_move, -3.5f, null), // 45
+ new mframe_t(ai_move, -0.2f, null), // 46
+ new mframe_t(ai_move, 0, null), // 47
+ new mframe_t(ai_move, -1.3f, null), // 48
+ new mframe_t(ai_move, -3, null), // 49
+ new mframe_t(ai_move, -2, null), // 50
+ new mframe_t(ai_move, 0, null), // 51
+ new mframe_t(ai_move, 0, null), // 52
+ new mframe_t(ai_move, 0, null), // 53
+ new mframe_t(ai_move, -3.3f, null), // 54
+ new mframe_t(ai_move, -1.6f, null), // 55
+ new mframe_t(ai_move, -0.3f, null), // 56
+ new mframe_t(ai_move, 0, null), // 57
+ new mframe_t(ai_move, 0, null), // 58
+ new mframe_t(ai_move, 0, null) // 59
+ };
+ static mmove_t insane_move_downtoup = new mmove_t(FRAME_stand41, FRAME_stand59, insane_frames_downtoup, insane_stand);
+
+ static mframe_t insane_frames_jumpdown[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0.2f, null),
+ new mframe_t(ai_move, 11.5f, null),
+ new mframe_t(ai_move, 5.1f, null),
+ new mframe_t(ai_move, 7.1f, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_jumpdown = new mmove_t(FRAME_stand96, FRAME_stand100, insane_frames_jumpdown, insane_onground);
+
+ static mframe_t insane_frames_down[] = new mframe_t[] { new mframe_t(ai_move, 0, null), // 100)
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 110)
+ new mframe_t(ai_move, -1.7f, null),
+ new mframe_t(ai_move, -1.6f, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, insane_fist),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 120)
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 130
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, insane_moan),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 140
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ // 150
+ new mframe_t(ai_move, 0.5f, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -0.2f, insane_scream),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0.2f, null),
+ new mframe_t(ai_move, 0.4f, null),
+ new mframe_t(ai_move, 0.6f, null),
+ new mframe_t(ai_move, 0.8f, null),
+ new mframe_t(ai_move, 0.7f, null),
+ new mframe_t(ai_move, 0, insane_checkup) // 160
+ };
+ static mmove_t insane_move_down = new mmove_t(FRAME_stand100, FRAME_stand160, insane_frames_down, insane_onground);
+
+ static mframe_t insane_frames_walk_normal[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 0, insane_scream),
+ new mframe_t(ai_walk, 2.5f, null),
+ new mframe_t(ai_walk, 3.5f, null),
+ new mframe_t(ai_walk, 1.7f, null),
+ new mframe_t(ai_walk, 2.3f, null),
+ new mframe_t(ai_walk, 2.4f, null),
+ new mframe_t(ai_walk, 2.2f, null),
+ new mframe_t(ai_walk, 4.2f, null),
+ new mframe_t(ai_walk, 5.6f, null),
+ new mframe_t(ai_walk, 3.3f, null),
+ new mframe_t(ai_walk, 2.4f, null),
+ new mframe_t(ai_walk, 0.9f, null),
+ new mframe_t(ai_walk, 0, null)};
+ static mmove_t insane_move_walk_normal = new mmove_t(FRAME_walk27, FRAME_walk39, insane_frames_walk_normal, insane_walk);
+
+ static mmove_t insane_move_run_normal = new mmove_t(FRAME_walk27, FRAME_walk39, insane_frames_walk_normal, insane_run);
+
+ static mframe_t insane_frames_walk_insane[] = new mframe_t[] { new mframe_t(ai_walk, 0, insane_scream), // walk 1
+ new mframe_t(ai_walk, 3.4f, null), // walk 2
+ new mframe_t(ai_walk, 3.6f, null), // 3
+ new mframe_t(ai_walk, 2.9f, null), // 4
+ new mframe_t(ai_walk, 2.2f, null), // 5
+ new mframe_t(ai_walk, 2.6f, null), // 6
+ new mframe_t(ai_walk, 0, null), // 7
+ new mframe_t(ai_walk, 0.7f, null), // 8
+ new mframe_t(ai_walk, 4.8f, null), // 9
+ new mframe_t(ai_walk, 5.3f, null), // 10
+ new mframe_t(ai_walk, 1.1f, null), // 11
+ new mframe_t(ai_walk, 2, null), // 12
+ new mframe_t(ai_walk, 0.5f, null), // 13
+ new mframe_t(ai_walk, 0, null), // 14
+ new mframe_t(ai_walk, 0, null), // 15
+ new mframe_t(ai_walk, 4.9f, null), // 16
+ new mframe_t(ai_walk, 6.7f, null), // 17
+ new mframe_t(ai_walk, 3.8f, null), // 18
+ new mframe_t(ai_walk, 2, null), // 19
+ new mframe_t(ai_walk, 0.2f, null), // 20
+ new mframe_t(ai_walk, 0, null), // 21
+ new mframe_t(ai_walk, 3.4f, null), // 22
+ new mframe_t(ai_walk, 6.4f, null), // 23
+ new mframe_t(ai_walk, 5, null), // 24
+ new mframe_t(ai_walk, 1.8f, null), // 25
+ new mframe_t(ai_walk, 0, null) // 26
+ };
+ static mmove_t insane_move_walk_insane = new mmove_t(FRAME_walk1, FRAME_walk26, insane_frames_walk_insane, insane_walk);
+
+ static mmove_t insane_move_run_insane = new mmove_t(FRAME_walk1, FRAME_walk26, insane_frames_walk_insane, insane_run);
+
+ static mframe_t insane_frames_stand_pain[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_stand_pain = new mmove_t(FRAME_st_pain2, FRAME_st_pain12, insane_frames_stand_pain, insane_run);
+
+ static mframe_t insane_frames_stand_death[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_stand_death = new mmove_t(FRAME_st_death2, FRAME_st_death18, insane_frames_stand_death, insane_dead);
+
+ static mframe_t insane_frames_crawl[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 0, insane_scream),
+ new mframe_t(ai_walk, 1.5f, null),
+ new mframe_t(ai_walk, 2.1f, null),
+ new mframe_t(ai_walk, 3.6f, null),
+ new mframe_t(ai_walk, 2f, null),
+ new mframe_t(ai_walk, 0.9f, null),
+ new mframe_t(ai_walk, 3f, null),
+ new mframe_t(ai_walk, 3.4f, null),
+ new mframe_t(ai_walk, 2.4f, null)};
+ static mmove_t insane_move_crawl = new mmove_t(FRAME_crawl1, FRAME_crawl9, insane_frames_crawl, null);
+
+ static mmove_t insane_move_runcrawl = new mmove_t(FRAME_crawl1, FRAME_crawl9, insane_frames_crawl, null);
+
+ static mframe_t insane_frames_crawl_pain[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_crawl_pain = new mmove_t(FRAME_cr_pain2, FRAME_cr_pain10, insane_frames_crawl_pain, insane_run);
+
+ static mframe_t insane_frames_crawl_death[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_crawl_death = new mmove_t(FRAME_cr_death10, FRAME_cr_death16, insane_frames_crawl_death, insane_dead);
+
+ static mframe_t insane_frames_cross[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, insane_moan),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_cross = new mmove_t(FRAME_cross1, FRAME_cross15, insane_frames_cross, insane_cross);
+
+ static mframe_t insane_frames_struggle_cross[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, insane_scream),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t insane_move_struggle_cross = new mmove_t(FRAME_cross16, FRAME_cross30, insane_frames_struggle_cross, insane_cross);
+
+ /*QUAKED misc_insane (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn CRAWL CRUCIFIED STAND_GROUND ALWAYS_STAND
+ */
+ static void SP_misc_insane(edict_t self) {
+ // static int skin = 0; //@@
+
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_fist = gi.soundindex("insane/insane11.wav");
+ sound_shake = gi.soundindex("insane/insane5.wav");
+ sound_moan = gi.soundindex("insane/insane7.wav");
+ sound_scream[0] = gi.soundindex("insane/insane1.wav");
+ sound_scream[1] = gi.soundindex("insane/insane2.wav");
+ sound_scream[2] = gi.soundindex("insane/insane3.wav");
+ sound_scream[3] = gi.soundindex("insane/insane4.wav");
+ sound_scream[4] = gi.soundindex("insane/insane6.wav");
+ sound_scream[5] = gi.soundindex("insane/insane8.wav");
+ sound_scream[6] = gi.soundindex("insane/insane9.wav");
+ sound_scream[7] = gi.soundindex("insane/insane10.wav");
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/insane/tris.md2");
+
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+
+ self.health = 100;
+ self.gib_health = -50;
+ self.mass = 300;
+
+ self.pain = insane_pain;
+ self.die = insane_die;
+
+ self.monsterinfo.stand = insane_stand;
+ self.monsterinfo.walk = insane_walk;
+ self.monsterinfo.run = insane_run;
+ self.monsterinfo.dodge = null;
+ self.monsterinfo.attack = null;
+ self.monsterinfo.melee = null;
+ self.monsterinfo.sight = null;
+ self.monsterinfo.aiflags |= AI_GOOD_GUY;
+
+ // @@
+ // self.s.skinnum = skin;
+ // skin++;
+ // if (skin > 12)
+ // skin = 0;
+
+ gi.linkentity(self);
+
+ if ((self.spawnflags & 16) != 0) // Stand Ground
+ self.monsterinfo.aiflags |= AI_STAND_GROUND;
+
+ self.monsterinfo.currentmove = insane_move_stand_normal;
+
+ self.monsterinfo.scale = MODEL_SCALE;
+ if ((self.spawnflags & 8) != 0) // Crucified ?
+ {
+ Math3D.VectorSet(self.mins, -16, 0, 0);
+ Math3D.VectorSet(self.maxs, 16, 8, 32);
+ self.flags |= FL_NO_KNOCKBACK;
+ flymonster_start.think(self);
+ } else {
+ walkmonster_start.think(self);
+ self.s.skinnum = Lib.rand() % 3;
+ }
+ }
+
+}
diff --git a/src/jake2/game/M_Medic.java b/src/jake2/game/M_Medic.java
new file mode 100644
index 0000000..322cc4d
--- /dev/null
+++ b/src/jake2/game/M_Medic.java
@@ -0,0 +1,1006 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Medic.java,v 1.1 2004-07-07 19:59:17 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Medic extends Game {
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_walk1 = 0;
+ public final static int FRAME_walk2 = 1;
+ public final static int FRAME_walk3 = 2;
+ public final static int FRAME_walk4 = 3;
+ public final static int FRAME_walk5 = 4;
+ public final static int FRAME_walk6 = 5;
+ public final static int FRAME_walk7 = 6;
+ public final static int FRAME_walk8 = 7;
+ public final static int FRAME_walk9 = 8;
+ public final static int FRAME_walk10 = 9;
+ public final static int FRAME_walk11 = 10;
+ public final static int FRAME_walk12 = 11;
+ public final static int FRAME_wait1 = 12;
+ public final static int FRAME_wait2 = 13;
+ public final static int FRAME_wait3 = 14;
+ public final static int FRAME_wait4 = 15;
+ public final static int FRAME_wait5 = 16;
+ public final static int FRAME_wait6 = 17;
+ public final static int FRAME_wait7 = 18;
+ public final static int FRAME_wait8 = 19;
+ public final static int FRAME_wait9 = 20;
+ public final static int FRAME_wait10 = 21;
+ public final static int FRAME_wait11 = 22;
+ public final static int FRAME_wait12 = 23;
+ public final static int FRAME_wait13 = 24;
+ public final static int FRAME_wait14 = 25;
+ public final static int FRAME_wait15 = 26;
+ public final static int FRAME_wait16 = 27;
+ public final static int FRAME_wait17 = 28;
+ public final static int FRAME_wait18 = 29;
+ public final static int FRAME_wait19 = 30;
+ public final static int FRAME_wait20 = 31;
+ public final static int FRAME_wait21 = 32;
+ public final static int FRAME_wait22 = 33;
+ public final static int FRAME_wait23 = 34;
+ public final static int FRAME_wait24 = 35;
+ public final static int FRAME_wait25 = 36;
+ public final static int FRAME_wait26 = 37;
+ public final static int FRAME_wait27 = 38;
+ public final static int FRAME_wait28 = 39;
+ public final static int FRAME_wait29 = 40;
+ public final static int FRAME_wait30 = 41;
+ public final static int FRAME_wait31 = 42;
+ public final static int FRAME_wait32 = 43;
+ public final static int FRAME_wait33 = 44;
+ public final static int FRAME_wait34 = 45;
+ public final static int FRAME_wait35 = 46;
+ public final static int FRAME_wait36 = 47;
+ public final static int FRAME_wait37 = 48;
+ public final static int FRAME_wait38 = 49;
+ public final static int FRAME_wait39 = 50;
+ public final static int FRAME_wait40 = 51;
+ public final static int FRAME_wait41 = 52;
+ public final static int FRAME_wait42 = 53;
+ public final static int FRAME_wait43 = 54;
+ public final static int FRAME_wait44 = 55;
+ public final static int FRAME_wait45 = 56;
+ public final static int FRAME_wait46 = 57;
+ public final static int FRAME_wait47 = 58;
+ public final static int FRAME_wait48 = 59;
+ public final static int FRAME_wait49 = 60;
+ public final static int FRAME_wait50 = 61;
+ public final static int FRAME_wait51 = 62;
+ public final static int FRAME_wait52 = 63;
+ public final static int FRAME_wait53 = 64;
+ public final static int FRAME_wait54 = 65;
+ public final static int FRAME_wait55 = 66;
+ public final static int FRAME_wait56 = 67;
+ public final static int FRAME_wait57 = 68;
+ public final static int FRAME_wait58 = 69;
+ public final static int FRAME_wait59 = 70;
+ public final static int FRAME_wait60 = 71;
+ public final static int FRAME_wait61 = 72;
+ public final static int FRAME_wait62 = 73;
+ public final static int FRAME_wait63 = 74;
+ public final static int FRAME_wait64 = 75;
+ public final static int FRAME_wait65 = 76;
+ public final static int FRAME_wait66 = 77;
+ public final static int FRAME_wait67 = 78;
+ public final static int FRAME_wait68 = 79;
+ public final static int FRAME_wait69 = 80;
+ public final static int FRAME_wait70 = 81;
+ public final static int FRAME_wait71 = 82;
+ public final static int FRAME_wait72 = 83;
+ public final static int FRAME_wait73 = 84;
+ public final static int FRAME_wait74 = 85;
+ public final static int FRAME_wait75 = 86;
+ public final static int FRAME_wait76 = 87;
+ public final static int FRAME_wait77 = 88;
+ public final static int FRAME_wait78 = 89;
+ public final static int FRAME_wait79 = 90;
+ public final static int FRAME_wait80 = 91;
+ public final static int FRAME_wait81 = 92;
+ public final static int FRAME_wait82 = 93;
+ public final static int FRAME_wait83 = 94;
+ public final static int FRAME_wait84 = 95;
+ public final static int FRAME_wait85 = 96;
+ public final static int FRAME_wait86 = 97;
+ public final static int FRAME_wait87 = 98;
+ public final static int FRAME_wait88 = 99;
+ public final static int FRAME_wait89 = 100;
+ public final static int FRAME_wait90 = 101;
+ public final static int FRAME_run1 = 102;
+ public final static int FRAME_run2 = 103;
+ public final static int FRAME_run3 = 104;
+ public final static int FRAME_run4 = 105;
+ public final static int FRAME_run5 = 106;
+ public final static int FRAME_run6 = 107;
+ public final static int FRAME_paina1 = 108;
+ public final static int FRAME_paina2 = 109;
+ public final static int FRAME_paina3 = 110;
+ public final static int FRAME_paina4 = 111;
+ public final static int FRAME_paina5 = 112;
+ public final static int FRAME_paina6 = 113;
+ public final static int FRAME_paina7 = 114;
+ public final static int FRAME_paina8 = 115;
+ public final static int FRAME_painb1 = 116;
+ public final static int FRAME_painb2 = 117;
+ public final static int FRAME_painb3 = 118;
+ public final static int FRAME_painb4 = 119;
+ public final static int FRAME_painb5 = 120;
+ public final static int FRAME_painb6 = 121;
+ public final static int FRAME_painb7 = 122;
+ public final static int FRAME_painb8 = 123;
+ public final static int FRAME_painb9 = 124;
+ public final static int FRAME_painb10 = 125;
+ public final static int FRAME_painb11 = 126;
+ public final static int FRAME_painb12 = 127;
+ public final static int FRAME_painb13 = 128;
+ public final static int FRAME_painb14 = 129;
+ public final static int FRAME_painb15 = 130;
+ public final static int FRAME_duck1 = 131;
+ public final static int FRAME_duck2 = 132;
+ public final static int FRAME_duck3 = 133;
+ public final static int FRAME_duck4 = 134;
+ public final static int FRAME_duck5 = 135;
+ public final static int FRAME_duck6 = 136;
+ public final static int FRAME_duck7 = 137;
+ public final static int FRAME_duck8 = 138;
+ public final static int FRAME_duck9 = 139;
+ public final static int FRAME_duck10 = 140;
+ public final static int FRAME_duck11 = 141;
+ public final static int FRAME_duck12 = 142;
+ public final static int FRAME_duck13 = 143;
+ public final static int FRAME_duck14 = 144;
+ public final static int FRAME_duck15 = 145;
+ public final static int FRAME_duck16 = 146;
+ public final static int FRAME_death1 = 147;
+ public final static int FRAME_death2 = 148;
+ public final static int FRAME_death3 = 149;
+ public final static int FRAME_death4 = 150;
+ public final static int FRAME_death5 = 151;
+ public final static int FRAME_death6 = 152;
+ public final static int FRAME_death7 = 153;
+ public final static int FRAME_death8 = 154;
+ public final static int FRAME_death9 = 155;
+ public final static int FRAME_death10 = 156;
+ public final static int FRAME_death11 = 157;
+ public final static int FRAME_death12 = 158;
+ public final static int FRAME_death13 = 159;
+ public final static int FRAME_death14 = 160;
+ public final static int FRAME_death15 = 161;
+ public final static int FRAME_death16 = 162;
+ public final static int FRAME_death17 = 163;
+ public final static int FRAME_death18 = 164;
+ public final static int FRAME_death19 = 165;
+ public final static int FRAME_death20 = 166;
+ public final static int FRAME_death21 = 167;
+ public final static int FRAME_death22 = 168;
+ public final static int FRAME_death23 = 169;
+ public final static int FRAME_death24 = 170;
+ public final static int FRAME_death25 = 171;
+ public final static int FRAME_death26 = 172;
+ public final static int FRAME_death27 = 173;
+ public final static int FRAME_death28 = 174;
+ public final static int FRAME_death29 = 175;
+ public final static int FRAME_death30 = 176;
+ public final static int FRAME_attack1 = 177;
+ public final static int FRAME_attack2 = 178;
+ public final static int FRAME_attack3 = 179;
+ public final static int FRAME_attack4 = 180;
+ public final static int FRAME_attack5 = 181;
+ public final static int FRAME_attack6 = 182;
+ public final static int FRAME_attack7 = 183;
+ public final static int FRAME_attack8 = 184;
+ public final static int FRAME_attack9 = 185;
+ public final static int FRAME_attack10 = 186;
+ public final static int FRAME_attack11 = 187;
+ public final static int FRAME_attack12 = 188;
+ public final static int FRAME_attack13 = 189;
+ public final static int FRAME_attack14 = 190;
+ public final static int FRAME_attack15 = 191;
+ public final static int FRAME_attack16 = 192;
+ public final static int FRAME_attack17 = 193;
+ public final static int FRAME_attack18 = 194;
+ public final static int FRAME_attack19 = 195;
+ public final static int FRAME_attack20 = 196;
+ public final static int FRAME_attack21 = 197;
+ public final static int FRAME_attack22 = 198;
+ public final static int FRAME_attack23 = 199;
+ public final static int FRAME_attack24 = 200;
+ public final static int FRAME_attack25 = 201;
+ public final static int FRAME_attack26 = 202;
+ public final static int FRAME_attack27 = 203;
+ public final static int FRAME_attack28 = 204;
+ public final static int FRAME_attack29 = 205;
+ public final static int FRAME_attack30 = 206;
+ public final static int FRAME_attack31 = 207;
+ public final static int FRAME_attack32 = 208;
+ public final static int FRAME_attack33 = 209;
+ public final static int FRAME_attack34 = 210;
+ public final static int FRAME_attack35 = 211;
+ public final static int FRAME_attack36 = 212;
+ public final static int FRAME_attack37 = 213;
+ public final static int FRAME_attack38 = 214;
+ public final static int FRAME_attack39 = 215;
+ public final static int FRAME_attack40 = 216;
+ public final static int FRAME_attack41 = 217;
+ public final static int FRAME_attack42 = 218;
+ public final static int FRAME_attack43 = 219;
+ public final static int FRAME_attack44 = 220;
+ public final static int FRAME_attack45 = 221;
+ public final static int FRAME_attack46 = 222;
+ public final static int FRAME_attack47 = 223;
+ public final static int FRAME_attack48 = 224;
+ public final static int FRAME_attack49 = 225;
+ public final static int FRAME_attack50 = 226;
+ public final static int FRAME_attack51 = 227;
+ public final static int FRAME_attack52 = 228;
+ public final static int FRAME_attack53 = 229;
+ public final static int FRAME_attack54 = 230;
+ public final static int FRAME_attack55 = 231;
+ public final static int FRAME_attack56 = 232;
+ public final static int FRAME_attack57 = 233;
+ public final static int FRAME_attack58 = 234;
+ public final static int FRAME_attack59 = 235;
+ public final static int FRAME_attack60 = 236;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_idle1;
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_die;
+ static int sound_sight;
+ static int sound_search;
+ static int sound_hook_launch;
+ static int sound_hook_hit;
+ static int sound_hook_heal;
+ static int sound_hook_retract;
+
+ static edict_t medic_FindDeadMonster(edict_t self) {
+ edict_t ent = null;
+ edict_t best = null;
+ EdictIterator edit = null;
+
+ while ((edit = findradius(edit, self.s.origin, 1024)) != null) {
+ ent = edit.o;
+ if (ent == self)
+ continue;
+ if (0 == (ent.svflags & SVF_MONSTER))
+ continue;
+ if ((ent.monsterinfo.aiflags & AI_GOOD_GUY) != 0)
+ continue;
+ if (ent.owner == null)
+ continue;
+ if (ent.health > 0)
+ continue;
+ if (ent.nextthink == 0)
+ continue;
+ if (!visible(self, ent))
+ continue;
+ if (best == null) {
+ best = ent;
+ continue;
+ }
+ if (ent.max_health <= best.max_health)
+ continue;
+ best = ent;
+ }
+
+ return best;
+ }
+
+ static EntThinkAdapter medic_idle = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent;
+
+ gi.sound(self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
+
+ ent = medic_FindDeadMonster(self);
+ if (ent != null) {
+ self.enemy = ent;
+ self.enemy.owner = self;
+ self.monsterinfo.aiflags |= AI_MEDIC;
+ FoundTarget(self);
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter medic_search = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ edict_t ent;
+
+ gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);
+
+ if (self.oldenemy == null) {
+ ent = medic_FindDeadMonster(self);
+ if (ent != null) {
+ self.oldenemy = self.enemy;
+ self.enemy = ent;
+ self.enemy.owner = self;
+ self.monsterinfo.aiflags |= AI_MEDIC;
+ FoundTarget(self);
+ }
+ }
+ return true;
+ }
+ };
+
+ static EntInteractAdapter medic_sight = new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, medic_idle),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ };
+ static mmove_t medic_move_stand = new mmove_t(FRAME_wait1, FRAME_wait90, medic_frames_stand, null);
+
+ static EntThinkAdapter medic_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = medic_move_stand;
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 6.2f, null),
+ new mframe_t(ai_walk, 18.1f, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 10, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 11, null),
+ new mframe_t(ai_walk, 11.6f, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 9.9f, null),
+ new mframe_t(ai_walk, 14, null),
+ new mframe_t(ai_walk, 9.3f, null)};
+ static mmove_t medic_move_walk = new mmove_t(FRAME_walk1, FRAME_walk12, medic_frames_walk, null);
+
+ static EntThinkAdapter medic_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = medic_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 18, null),
+ new mframe_t(ai_run, 22.5f, null),
+ new mframe_t(ai_run, 25.4f, null),
+ new mframe_t(ai_run, 23.4f, null),
+ new mframe_t(ai_run, 24, null),
+ new mframe_t(ai_run, 35.6f, null)};
+ static mmove_t medic_move_run = new mmove_t(FRAME_run1, FRAME_run6, medic_frames_run, null);
+
+ static EntThinkAdapter medic_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (0 == (self.monsterinfo.aiflags & AI_MEDIC)) {
+ edict_t ent;
+
+ ent = medic_FindDeadMonster(self);
+ if (ent != null) {
+ self.oldenemy = self.enemy;
+ self.enemy = ent;
+ self.enemy.owner = self;
+ self.monsterinfo.aiflags |= AI_MEDIC;
+ FoundTarget(self);
+ return true;
+ }
+ }
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove = medic_move_stand;
+ else
+ self.monsterinfo.currentmove = medic_move_run;
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t medic_move_pain1 = new mmove_t(FRAME_paina1, FRAME_paina8, medic_frames_pain1, medic_run);
+
+ static mframe_t medic_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t medic_move_pain2 = new mmove_t(FRAME_painb1, FRAME_painb15, medic_frames_pain2, medic_run);
+ static EntPainAdapter medic_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (Lib.random() < 0.5) {
+ self.monsterinfo.currentmove = medic_move_pain1;
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ } else {
+ self.monsterinfo.currentmove = medic_move_pain2;
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ }
+ }
+ };
+
+ static EntThinkAdapter medic_fire_blaster = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] start={0,0,0};
+ float[] forward={0,0,0}, right={0,0,0};
+ float[] end={0,0,0};
+ float[] dir={0,0,0};
+ int effect;
+
+ if ((self.s.frame == FRAME_attack9) || (self.s.frame == FRAME_attack12))
+ effect = EF_BLASTER;
+ else if (
+ (self.s.frame == FRAME_attack19)
+ || (self.s.frame == FRAME_attack22)
+ || (self.s.frame == FRAME_attack25)
+ || (self.s.frame == FRAME_attack28))
+ effect = EF_HYPERBLASTER;
+ else
+ effect = 0;
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[MZ2_MEDIC_BLASTER_1], forward, right, start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ end[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(end, start, dir);
+
+ Monster.monster_fire_blaster(self, start, dir, 2, 1000, MZ2_MEDIC_BLASTER_1, effect);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter medic_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink = 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_death[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t medic_move_death = new mmove_t(FRAME_death1, FRAME_death30, medic_frames_death, medic_dead);
+
+ static EntDieAdapter medic_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+
+ int n;
+
+ // if we had a pending patient, free him up for another medic
+ if ((self.enemy != null) && (self.enemy.owner == self))
+ self.enemy.owner = null;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+
+ self.monsterinfo.currentmove = medic_move_death;
+ }
+ };
+
+ static EntThinkAdapter medic_duck_down = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_DUCKED) != 0)
+ return true;
+ self.monsterinfo.aiflags |= AI_DUCKED;
+ self.maxs[2] -= 32;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.pausetime = level.time + 1;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter medic_duck_hold = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter medic_duck_up = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.aiflags &= ~AI_DUCKED;
+ self.maxs[2] += 32;
+ self.takedamage = DAMAGE_AIM;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_duck[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, medic_duck_down),
+ new mframe_t(ai_move, -1, medic_duck_hold),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, medic_duck_up),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null)};
+ static mmove_t medic_move_duck = new mmove_t(FRAME_duck1, FRAME_duck16, medic_frames_duck, medic_run);
+
+ static EntDodgeAdapter medic_dodge = new EntDodgeAdapter() {
+ public void dodge(edict_t self, edict_t attacker, float eta) {
+ if (Lib.random() > 0.25)
+ return;
+
+ if (self.enemy == null)
+ self.enemy = attacker;
+
+ self.monsterinfo.currentmove = medic_move_duck;
+ }
+ };
+
+ static mframe_t medic_frames_attackHyperBlaster[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, medic_fire_blaster)};
+ static mmove_t medic_move_attackHyperBlaster =
+ new mmove_t(FRAME_attack15, FRAME_attack30, medic_frames_attackHyperBlaster, medic_run);
+
+ static EntThinkAdapter medic_continue = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (visible(self, self.enemy))
+ if (Lib.random() <= 0.95)
+ self.monsterinfo.currentmove = medic_move_attackHyperBlaster;
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_attackBlaster[] =
+ {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, medic_fire_blaster),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, medic_continue) // Change to medic_continue... Else, go to frame 32
+ };
+ static mmove_t medic_move_attackBlaster = new mmove_t(FRAME_attack1, FRAME_attack14, medic_frames_attackBlaster, medic_run);
+
+ static EntThinkAdapter medic_hook_launch = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_hook_launch, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static float medic_cable_offsets[][] = { { 45.0f, -9.2f, 15.5f }, {
+ 48.4f, -9.7f, 15.2f }, {
+ 47.8f, -9.8f, 15.8f }, {
+ 47.3f, -9.3f, 14.3f }, {
+ 45.4f, -10.1f, 13.1f }, {
+ 41.9f, -12.7f, 12.0f }, {
+ 37.8f, -15.8f, 11.2f }, {
+ 34.3f, -18.4f, 10.7f }, {
+ 32.7f, -19.7f, 10.4f }, {
+ 32.7f, -19.7f, 10.4f }
+ };
+
+ static EntThinkAdapter medic_cable_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] offset={0,0,0}, start={0,0,0}, end={0,0,0}, f={0,0,0}, r={0,0,0};
+ trace_t tr;
+ float[] dir={0,0,0}, angles={0,0,0};
+ float distance;
+
+ if (!self.enemy.inuse)
+ return true;
+
+ Math3D.AngleVectors(self.s.angles, f, r, null);
+ Math3D.VectorCopy(medic_cable_offsets[self.s.frame - FRAME_attack42], offset);
+ Math3D.G_ProjectSource(self.s.origin, offset, f, r, start);
+
+ // check for max distance
+ Math3D.VectorSubtract(start, self.enemy.s.origin, dir);
+ distance = Math3D.VectorLength(dir);
+ if (distance > 256)
+ return true;
+
+ // check for min/max pitch
+ Math3D.vectoangles(dir, angles);
+ if (angles[0] < -180)
+ angles[0] += 360;
+ if (Math.abs(angles[0]) > 45)
+ return true;
+
+ tr = gi.trace(start, null, null, self.enemy.s.origin, self, MASK_SHOT);
+ if (tr.fraction != 1.0 && tr.ent != self.enemy)
+ return true;
+
+ if (self.s.frame == FRAME_attack43) {
+ gi.sound(self.enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
+ self.enemy.monsterinfo.aiflags |= AI_RESURRECTING;
+ } else if (self.s.frame == FRAME_attack50) {
+ self.enemy.spawnflags = 0;
+ self.enemy.monsterinfo.aiflags = 0;
+ self.enemy.target = null;
+ self.enemy.targetname = null;
+ self.enemy.combattarget = null;
+ self.enemy.deathtarget = null;
+ self.enemy.owner = self;
+ GameSpawn.ED_CallSpawn(self.enemy);
+ self.enemy.owner = null;
+ if (self.enemy.think != null) {
+ self.enemy.nextthink = level.time;
+ self.enemy.think.think(self.enemy);
+ }
+ self.enemy.monsterinfo.aiflags |= AI_RESURRECTING;
+ if (self.oldenemy != null && self.oldenemy.client != null) {
+ self.enemy.enemy = self.oldenemy;
+ FoundTarget(self.enemy);
+ }
+ } else {
+ if (self.s.frame == FRAME_attack44)
+ gi.sound(self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
+ }
+
+ // adjust start for beam origin being in middle of a segment
+ Math3D.VectorMA(start, 8, f, start);
+
+ // adjust end z for end spot since the monster is currently dead
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ end[2] = self.enemy.absmin[2] + self.enemy.size[2] / 2;
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_MEDIC_CABLE_ATTACK);
+ gi.WriteShort(self.index);
+ gi.WritePosition(start);
+ gi.WritePosition(end);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter medic_hook_retract = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_hook_retract, 1, ATTN_NORM, 0);
+ self.enemy.monsterinfo.aiflags &= ~AI_RESURRECTING;
+ return true;
+ }
+ };
+
+ static mframe_t medic_frames_attackCable[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, 4.4f, null),
+ new mframe_t(ai_charge, 4.7f, null),
+ new mframe_t(ai_charge, 5, null),
+ new mframe_t(ai_charge, 6, null),
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_move, 0, medic_hook_launch),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, 0, medic_cable_attack),
+ new mframe_t(ai_move, -15, medic_hook_retract),
+ new mframe_t(ai_move, -1.5f, null),
+ new mframe_t(ai_move, -1.2f, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 0.3f, null),
+ new mframe_t(ai_move, 0.7f, null),
+ new mframe_t(ai_move, 1.2f, null),
+ new mframe_t(ai_move, 1.3f, null)};
+ static mmove_t medic_move_attackCable = new mmove_t(FRAME_attack33, FRAME_attack60, medic_frames_attackCable, medic_run);
+
+ static EntThinkAdapter medic_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_MEDIC) != 0)
+ self.monsterinfo.currentmove = medic_move_attackCable;
+ else
+ self.monsterinfo.currentmove = medic_move_attackBlaster;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter medic_checkattack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_MEDIC) != 0) {
+ medic_attack.think(self);
+ return true;
+ }
+
+ return M_CheckAttack.think(self);
+
+ }
+ };
+
+ /*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static void SP_monster_medic(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ sound_idle1 = gi.soundindex("medic/idle.wav");
+ sound_pain1 = gi.soundindex("medic/medpain1.wav");
+ sound_pain2 = gi.soundindex("medic/medpain2.wav");
+ sound_die = gi.soundindex("medic/meddeth1.wav");
+ sound_sight = gi.soundindex("medic/medsght1.wav");
+ sound_search = gi.soundindex("medic/medsrch1.wav");
+ sound_hook_launch = gi.soundindex("medic/medatck2.wav");
+ sound_hook_hit = gi.soundindex("medic/medatck3.wav");
+ sound_hook_heal = gi.soundindex("medic/medatck4.wav");
+ sound_hook_retract = gi.soundindex("medic/medatck5.wav");
+
+ gi.soundindex("medic/medatck1.wav");
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/medic/tris.md2");
+ Math3D.VectorSet(self.mins, -24, -24, -24);
+ Math3D.VectorSet(self.maxs, 24, 24, 32);
+
+ self.health = 300;
+ self.gib_health = -130;
+ self.mass = 400;
+
+ self.pain = medic_pain;
+ self.die = medic_die;
+
+ self.monsterinfo.stand = medic_stand;
+ self.monsterinfo.walk = medic_walk;
+ self.monsterinfo.run = medic_run;
+ self.monsterinfo.dodge = medic_dodge;
+ self.monsterinfo.attack = medic_attack;
+ self.monsterinfo.melee = null;
+ self.monsterinfo.sight = medic_sight;
+ self.monsterinfo.idle = medic_idle;
+ self.monsterinfo.search = medic_search;
+ self.monsterinfo.checkattack = medic_checkattack;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = medic_move_stand;
+ self.monsterinfo.scale = MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ }
+
+}
diff --git a/src/jake2/game/M_Mutant.java b/src/jake2/game/M_Mutant.java
new file mode 100644
index 0000000..b25ffc9
--- /dev/null
+++ b/src/jake2/game/M_Mutant.java
@@ -0,0 +1,834 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Mutant.java,v 1.1 2004-07-07 19:59:17 hzi Exp $
+
+package jake2.game;
+
+import jake2.client.M;
+import jake2.util.*;
+
+public class M_Mutant extends Game {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_attack01 = 0;
+ public final static int FRAME_attack02 = 1;
+ public final static int FRAME_attack03 = 2;
+ public final static int FRAME_attack04 = 3;
+ public final static int FRAME_attack05 = 4;
+ public final static int FRAME_attack06 = 5;
+ public final static int FRAME_attack07 = 6;
+ public final static int FRAME_attack08 = 7;
+ public final static int FRAME_attack09 = 8;
+ public final static int FRAME_attack10 = 9;
+ public final static int FRAME_attack11 = 10;
+ public final static int FRAME_attack12 = 11;
+ public final static int FRAME_attack13 = 12;
+ public final static int FRAME_attack14 = 13;
+ public final static int FRAME_attack15 = 14;
+ public final static int FRAME_death101 = 15;
+ public final static int FRAME_death102 = 16;
+ public final static int FRAME_death103 = 17;
+ public final static int FRAME_death104 = 18;
+ public final static int FRAME_death105 = 19;
+ public final static int FRAME_death106 = 20;
+ public final static int FRAME_death107 = 21;
+ public final static int FRAME_death108 = 22;
+ public final static int FRAME_death109 = 23;
+ public final static int FRAME_death201 = 24;
+ public final static int FRAME_death202 = 25;
+ public final static int FRAME_death203 = 26;
+ public final static int FRAME_death204 = 27;
+ public final static int FRAME_death205 = 28;
+ public final static int FRAME_death206 = 29;
+ public final static int FRAME_death207 = 30;
+ public final static int FRAME_death208 = 31;
+ public final static int FRAME_death209 = 32;
+ public final static int FRAME_death210 = 33;
+ public final static int FRAME_pain101 = 34;
+ public final static int FRAME_pain102 = 35;
+ public final static int FRAME_pain103 = 36;
+ public final static int FRAME_pain104 = 37;
+ public final static int FRAME_pain105 = 38;
+ public final static int FRAME_pain201 = 39;
+ public final static int FRAME_pain202 = 40;
+ public final static int FRAME_pain203 = 41;
+ public final static int FRAME_pain204 = 42;
+ public final static int FRAME_pain205 = 43;
+ public final static int FRAME_pain206 = 44;
+ public final static int FRAME_pain301 = 45;
+ public final static int FRAME_pain302 = 46;
+ public final static int FRAME_pain303 = 47;
+ public final static int FRAME_pain304 = 48;
+ public final static int FRAME_pain305 = 49;
+ public final static int FRAME_pain306 = 50;
+ public final static int FRAME_pain307 = 51;
+ public final static int FRAME_pain308 = 52;
+ public final static int FRAME_pain309 = 53;
+ public final static int FRAME_pain310 = 54;
+ public final static int FRAME_pain311 = 55;
+ public final static int FRAME_run03 = 56;
+ public final static int FRAME_run04 = 57;
+ public final static int FRAME_run05 = 58;
+ public final static int FRAME_run06 = 59;
+ public final static int FRAME_run07 = 60;
+ public final static int FRAME_run08 = 61;
+ public final static int FRAME_stand101 = 62;
+ public final static int FRAME_stand102 = 63;
+ public final static int FRAME_stand103 = 64;
+ public final static int FRAME_stand104 = 65;
+ public final static int FRAME_stand105 = 66;
+ public final static int FRAME_stand106 = 67;
+ public final static int FRAME_stand107 = 68;
+ public final static int FRAME_stand108 = 69;
+ public final static int FRAME_stand109 = 70;
+ public final static int FRAME_stand110 = 71;
+ public final static int FRAME_stand111 = 72;
+ public final static int FRAME_stand112 = 73;
+ public final static int FRAME_stand113 = 74;
+ public final static int FRAME_stand114 = 75;
+ public final static int FRAME_stand115 = 76;
+ public final static int FRAME_stand116 = 77;
+ public final static int FRAME_stand117 = 78;
+ public final static int FRAME_stand118 = 79;
+ public final static int FRAME_stand119 = 80;
+ public final static int FRAME_stand120 = 81;
+ public final static int FRAME_stand121 = 82;
+ public final static int FRAME_stand122 = 83;
+ public final static int FRAME_stand123 = 84;
+ public final static int FRAME_stand124 = 85;
+ public final static int FRAME_stand125 = 86;
+ public final static int FRAME_stand126 = 87;
+ public final static int FRAME_stand127 = 88;
+ public final static int FRAME_stand128 = 89;
+ public final static int FRAME_stand129 = 90;
+ public final static int FRAME_stand130 = 91;
+ public final static int FRAME_stand131 = 92;
+ public final static int FRAME_stand132 = 93;
+ public final static int FRAME_stand133 = 94;
+ public final static int FRAME_stand134 = 95;
+ public final static int FRAME_stand135 = 96;
+ public final static int FRAME_stand136 = 97;
+ public final static int FRAME_stand137 = 98;
+ public final static int FRAME_stand138 = 99;
+ public final static int FRAME_stand139 = 100;
+ public final static int FRAME_stand140 = 101;
+ public final static int FRAME_stand141 = 102;
+ public final static int FRAME_stand142 = 103;
+ public final static int FRAME_stand143 = 104;
+ public final static int FRAME_stand144 = 105;
+ public final static int FRAME_stand145 = 106;
+ public final static int FRAME_stand146 = 107;
+ public final static int FRAME_stand147 = 108;
+ public final static int FRAME_stand148 = 109;
+ public final static int FRAME_stand149 = 110;
+ public final static int FRAME_stand150 = 111;
+ public final static int FRAME_stand151 = 112;
+ public final static int FRAME_stand152 = 113;
+ public final static int FRAME_stand153 = 114;
+ public final static int FRAME_stand154 = 115;
+ public final static int FRAME_stand155 = 116;
+ public final static int FRAME_stand156 = 117;
+ public final static int FRAME_stand157 = 118;
+ public final static int FRAME_stand158 = 119;
+ public final static int FRAME_stand159 = 120;
+ public final static int FRAME_stand160 = 121;
+ public final static int FRAME_stand161 = 122;
+ public final static int FRAME_stand162 = 123;
+ public final static int FRAME_stand163 = 124;
+ public final static int FRAME_stand164 = 125;
+ public final static int FRAME_walk01 = 126;
+ public final static int FRAME_walk02 = 127;
+ public final static int FRAME_walk03 = 128;
+ public final static int FRAME_walk04 = 129;
+ public final static int FRAME_walk05 = 130;
+ public final static int FRAME_walk06 = 131;
+ public final static int FRAME_walk07 = 132;
+ public final static int FRAME_walk08 = 133;
+ public final static int FRAME_walk09 = 134;
+ public final static int FRAME_walk10 = 135;
+ public final static int FRAME_walk11 = 136;
+ public final static int FRAME_walk12 = 137;
+ public final static int FRAME_walk13 = 138;
+ public final static int FRAME_walk14 = 139;
+ public final static int FRAME_walk15 = 140;
+ public final static int FRAME_walk16 = 141;
+ public final static int FRAME_walk17 = 142;
+ public final static int FRAME_walk18 = 143;
+ public final static int FRAME_walk19 = 144;
+ public final static int FRAME_walk20 = 145;
+ public final static int FRAME_walk21 = 146;
+ public final static int FRAME_walk22 = 147;
+ public final static int FRAME_walk23 = 148;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_swing;
+ static int sound_hit;
+ static int sound_hit2;
+ static int sound_death;
+ static int sound_idle;
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_sight;
+ static int sound_search;
+ static int sound_step1;
+ static int sound_step2;
+ static int sound_step3;
+ static int sound_thud;
+
+ //
+ // SOUNDS
+ //
+ static EntThinkAdapter mutant_step = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ int n;
+ n = (Lib.rand() + 1) % 3;
+ if (n == 0)
+ gi.sound(self, CHAN_VOICE, sound_step1, 1, ATTN_NORM, 0);
+ else if (n == 1)
+ gi.sound(self, CHAN_VOICE, sound_step2, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_step3, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntInteractAdapter mutant_sight = new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+
+ static EntThinkAdapter mutant_search = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+ static EntThinkAdapter mutant_swing = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_swing, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ //
+ // STAND
+ //
+
+ static mframe_t mutant_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 10)
+
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 20)
+
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 30)
+
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 40)
+
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // 50)
+
+ new mframe_t(ai_stand, 0, null)};
+
+ static mmove_t mutant_move_stand = new mmove_t(FRAME_stand101, FRAME_stand151, mutant_frames_stand, null);
+
+ static EntThinkAdapter mutant_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = mutant_move_stand;
+ return true;
+ }
+ };
+
+ //
+ // IDLE
+ //
+
+ static EntThinkAdapter mutant_idle_loop = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() < 0.75)
+ self.monsterinfo.nextframe = FRAME_stand155;
+ return true;
+ }
+ };
+
+ static mframe_t mutant_frames_idle[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ // scratch loop start
+ new mframe_t(ai_stand, 0, null), new mframe_t(ai_stand, 0, null), new mframe_t(ai_stand, 0, mutant_idle_loop),
+ // scratch loop end
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+
+ static mmove_t mutant_move_idle = new mmove_t(FRAME_stand152, FRAME_stand164, mutant_frames_idle, mutant_stand);
+
+ static EntThinkAdapter mutant_idle = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = mutant_move_idle;
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ //
+ // WALK
+ //
+
+ static mframe_t mutant_frames_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 10, null),
+ new mframe_t(ai_walk, 13, null),
+ new mframe_t(ai_walk, 10, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 16, null),
+ new mframe_t(ai_walk, 15, null),
+ new mframe_t(ai_walk, 6, null)};
+ static mmove_t mutant_move_walk = new mmove_t(FRAME_walk05, FRAME_walk16, mutant_frames_walk, null);
+
+ static EntThinkAdapter mutant_walk_loop = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = mutant_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t mutant_frames_start_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, -2, null),
+ new mframe_t(ai_walk, 1, null)};
+
+ static mmove_t mutant_move_start_walk = new mmove_t(FRAME_walk01, FRAME_walk04, mutant_frames_start_walk, mutant_walk_loop);
+
+ static EntThinkAdapter mutant_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = mutant_move_start_walk;
+ return true;
+ }
+ };
+
+
+ //
+ // RUN
+ //
+
+ static mframe_t mutant_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 40, null),
+ new mframe_t(ai_run, 40, mutant_step),
+ new mframe_t(ai_run, 24, null),
+ new mframe_t(ai_run, 5, mutant_step),
+ new mframe_t(ai_run, 17, null),
+ new mframe_t(ai_run, 10, null)};
+ static mmove_t mutant_move_run = new mmove_t(FRAME_run03, FRAME_run08, mutant_frames_run, null);
+
+ static EntThinkAdapter mutant_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND)!=0)
+ self.monsterinfo.currentmove = mutant_move_stand;
+ else
+ self.monsterinfo.currentmove = mutant_move_run;
+
+ return true;
+ }
+ };
+
+ //
+ // MELEE
+ //
+
+ static EntThinkAdapter mutant_hit_left = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim={0,0,0};
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.mins[0], 8);
+ if (Fire.fire_hit(self, aim, (10 + (Lib.rand() % 5)), 100))
+ gi.sound(self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter mutant_hit_right = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] aim={0,0,0};
+
+ Math3D.VectorSet(aim, MELEE_DISTANCE, self.maxs[0], 8);
+ if (Fire.fire_hit(self, aim, (10 + (Lib.rand() % 5)), 100))
+ gi.sound(self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter mutant_check_refire = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (null == self.enemy || !self.enemy.inuse || self.enemy.health <= 0)
+ return true;
+
+ if (((skill.value == 3) && (Lib.random() < 0.5)) || (range(self, self.enemy) == RANGE_MELEE))
+ self.monsterinfo.nextframe = FRAME_attack09;
+ return true;
+ }
+ };
+
+ static mframe_t mutant_frames_attack[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, mutant_hit_left),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, mutant_hit_right),
+ new mframe_t(ai_charge, 0, mutant_check_refire)};
+ static mmove_t mutant_move_attack = new mmove_t(FRAME_attack09, FRAME_attack15, mutant_frames_attack, mutant_run);
+
+ static EntThinkAdapter mutant_melee = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = mutant_move_attack;
+ return true;
+ }
+ };
+
+ //
+ // ATTACK
+ //
+
+ static EntTouchAdapter mutant_jump_touch = new EntTouchAdapter() {
+
+ public void touch(edict_t self, edict_t other, cplane_t plane, csurface_t surf) {
+ if (self.health <= 0) {
+ self.touch = null;
+ return;
+ }
+
+ if (other.takedamage!=0) {
+ if (Math3D.VectorLength(self.velocity) > 400) {
+ float[] point={0,0,0};
+ float[] normal={0,0,0};
+ int damage;
+
+ Math3D.VectorCopy(self.velocity, normal);
+ Math3D.VectorNormalize(normal);
+ Math3D.VectorMA(self.s.origin, self.maxs[0], normal, point);
+ damage = (int) (40 + 10 * Lib.random());
+ T_Damage(other, self, self, self.velocity, point, normal, damage, damage, 0, MOD_UNKNOWN);
+ }
+ }
+
+ if (!M.M_CheckBottom(self)) {
+ if (self.groundentity != null) {
+ self.monsterinfo.nextframe = FRAME_attack02;
+ self.touch = null;
+ }
+ return;
+ }
+
+ self.touch = null;
+ }
+ };
+
+ static EntThinkAdapter mutant_jump_takeoff = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] forward={0,0,0};
+
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ Math3D.AngleVectors(self.s.angles, forward, null, null);
+ self.s.origin[2] += 1;
+ Math3D.VectorScale(forward, 600, self.velocity);
+ self.velocity[2] = 250;
+ self.groundentity = null;
+ self.monsterinfo.aiflags |= AI_DUCKED;
+ self.monsterinfo.attack_finished = level.time + 3;
+ self.touch = mutant_jump_touch;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter mutant_check_landing = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.groundentity != null) {
+ gi.sound(self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
+ self.monsterinfo.attack_finished = 0;
+ self.monsterinfo.aiflags &= ~AI_DUCKED;
+ return true;
+ }
+
+ if (level.time > self.monsterinfo.attack_finished)
+ self.monsterinfo.nextframe = FRAME_attack02;
+ else
+ self.monsterinfo.nextframe = FRAME_attack05;
+ return true;
+ }
+ };
+
+ static mframe_t mutant_frames_jump[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 17, null),
+ new mframe_t(ai_charge, 15, mutant_jump_takeoff),
+ new mframe_t(ai_charge, 15, null),
+ new mframe_t(ai_charge, 15, mutant_check_landing),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t mutant_move_jump = new mmove_t(FRAME_attack01, FRAME_attack08, mutant_frames_jump, mutant_run);
+
+ static EntThinkAdapter mutant_jump = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.monsterinfo.currentmove = mutant_move_jump;
+ return true;
+ }
+ };
+
+ //
+ // CHECKATTACK
+ //
+ static EntThinkAdapter mutant_check_melee = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (range(self, self.enemy) == RANGE_MELEE)
+ return true;
+ return false;
+
+ }
+ };
+
+ static EntThinkAdapter mutant_check_jump = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] v={0,0,0};
+ float distance;
+
+ if (self.absmin[2] > (self.enemy.absmin[2] + 0.75 * self.enemy.size[2]))
+ return false;
+
+ if (self.absmax[2] < (self.enemy.absmin[2] + 0.25 * self.enemy.size[2]))
+ return false;
+
+ v[0] = self.s.origin[0] - self.enemy.s.origin[0];
+ v[1] = self.s.origin[1] - self.enemy.s.origin[1];
+ v[2] = 0;
+ distance = Math3D.VectorLength(v);
+
+ if (distance < 100)
+ return false;
+ if (distance > 100) {
+ if (Lib.random() < 0.9)
+ return false;
+ }
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter mutant_checkattack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if (null==self.enemy || self.enemy.health <= 0)
+ return false;
+
+ if (mutant_check_melee.think(self)) {
+ self.monsterinfo.attack_state = AS_MELEE;
+ return true;
+ }
+
+ if (mutant_check_jump.think(self)) {
+ self.monsterinfo.attack_state = AS_MISSILE;
+ // FIXME play a jump sound here
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+ //
+ // PAIN
+ //
+
+ static mframe_t mutant_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -8, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 5, null)};
+ static mmove_t mutant_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain105, mutant_frames_pain1, mutant_run);
+
+ static mframe_t mutant_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -24, null),
+ new mframe_t(ai_move, 11, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 4, null)};
+ static mmove_t mutant_move_pain2 = new mmove_t(FRAME_pain201, FRAME_pain206, mutant_frames_pain2, mutant_run);
+
+ static mframe_t mutant_frames_pain3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -22, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 1, null)};
+ static mmove_t mutant_move_pain3 = new mmove_t(FRAME_pain301, FRAME_pain311, mutant_frames_pain3, mutant_run);
+
+ static EntPainAdapter mutant_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ float r;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ r = Lib.random();
+ if (r < 0.33) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = mutant_move_pain1;
+ } else if (r < 0.66) {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = mutant_move_pain2;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = mutant_move_pain3;
+ }
+ }
+ };
+
+ //
+ // DEATH
+ //
+ static EntThinkAdapter mutant_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ gi.linkentity(self);
+
+ M.M_FlyCheck.think(self);
+ return true;
+ }
+ };
+
+ static mframe_t mutant_frames_death1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t mutant_move_death1 = new mmove_t(FRAME_death101, FRAME_death109, mutant_frames_death1, mutant_dead);
+
+ static mframe_t mutant_frames_death2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t mutant_move_death2 = new mmove_t(FRAME_death201, FRAME_death210, mutant_frames_death2, mutant_dead);
+
+ static EntDieAdapter mutant_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+ self.s.skinnum = 1;
+
+ if (Lib.random() < 0.5)
+ self.monsterinfo.currentmove = mutant_move_death1;
+ else
+ self.monsterinfo.currentmove = mutant_move_death2;
+ }
+ };
+
+ //
+ // SPAWN
+ //
+
+ /*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight
+ */
+ static EntThinkAdapter SP_monster_mutant = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (deathmatch.value!=0) {
+ G_FreeEdict(self);
+ return false;
+ }
+
+ sound_swing = gi.soundindex("mutant/mutatck1.wav");
+ sound_hit = gi.soundindex("mutant/mutatck2.wav");
+ sound_hit2 = gi.soundindex("mutant/mutatck3.wav");
+ sound_death = gi.soundindex("mutant/mutdeth1.wav");
+ sound_idle = gi.soundindex("mutant/mutidle1.wav");
+ sound_pain1 = gi.soundindex("mutant/mutpain1.wav");
+ sound_pain2 = gi.soundindex("mutant/mutpain2.wav");
+ sound_sight = gi.soundindex("mutant/mutsght1.wav");
+ sound_search = gi.soundindex("mutant/mutsrch1.wav");
+ sound_step1 = gi.soundindex("mutant/step1.wav");
+ sound_step2 = gi.soundindex("mutant/step2.wav");
+ sound_step3 = gi.soundindex("mutant/step3.wav");
+ sound_thud = gi.soundindex("mutant/thud1.wav");
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/mutant/tris.md2");
+ Math3D.VectorSet(self.mins, -32, -32, -24);
+ Math3D.VectorSet(self.maxs, 32, 32, 48);
+
+ self.health = 300;
+ self.gib_health = -120;
+ self.mass = 300;
+
+ self.pain = mutant_pain;
+ self.die = mutant_die;
+
+ self.monsterinfo.stand = mutant_stand;
+ self.monsterinfo.walk = mutant_walk;
+ self.monsterinfo.run = mutant_run;
+ self.monsterinfo.dodge = null;
+ self.monsterinfo.attack = mutant_jump;
+ self.monsterinfo.melee = mutant_melee;
+ self.monsterinfo.sight = mutant_sight;
+ self.monsterinfo.search = mutant_search;
+ self.monsterinfo.idle = mutant_idle;
+ self.monsterinfo.checkattack = mutant_checkattack;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = mutant_move_stand;
+
+ self.monsterinfo.scale = MODEL_SCALE;
+ walkmonster_start.think(self);
+ return true;
+ }
+ };
+} \ No newline at end of file
diff --git a/src/jake2/game/M_Parasite.java b/src/jake2/game/M_Parasite.java
new file mode 100644
index 0000000..78d6d34
--- /dev/null
+++ b/src/jake2/game/M_Parasite.java
@@ -0,0 +1,675 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Parasite.java,v 1.1 2004-07-07 19:59:18 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Parasite extends GamePWeapon {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_break01 = 0;
+ public final static int FRAME_break02 = 1;
+ public final static int FRAME_break03 = 2;
+ public final static int FRAME_break04 = 3;
+ public final static int FRAME_break05 = 4;
+ public final static int FRAME_break06 = 5;
+ public final static int FRAME_break07 = 6;
+ public final static int FRAME_break08 = 7;
+ public final static int FRAME_break09 = 8;
+ public final static int FRAME_break10 = 9;
+ public final static int FRAME_break11 = 10;
+ public final static int FRAME_break12 = 11;
+ public final static int FRAME_break13 = 12;
+ public final static int FRAME_break14 = 13;
+ public final static int FRAME_break15 = 14;
+ public final static int FRAME_break16 = 15;
+ public final static int FRAME_break17 = 16;
+ public final static int FRAME_break18 = 17;
+ public final static int FRAME_break19 = 18;
+ public final static int FRAME_break20 = 19;
+ public final static int FRAME_break21 = 20;
+ public final static int FRAME_break22 = 21;
+ public final static int FRAME_break23 = 22;
+ public final static int FRAME_break24 = 23;
+ public final static int FRAME_break25 = 24;
+ public final static int FRAME_break26 = 25;
+ public final static int FRAME_break27 = 26;
+ public final static int FRAME_break28 = 27;
+ public final static int FRAME_break29 = 28;
+ public final static int FRAME_break30 = 29;
+ public final static int FRAME_break31 = 30;
+ public final static int FRAME_break32 = 31;
+ public final static int FRAME_death101 = 32;
+ public final static int FRAME_death102 = 33;
+ public final static int FRAME_death103 = 34;
+ public final static int FRAME_death104 = 35;
+ public final static int FRAME_death105 = 36;
+ public final static int FRAME_death106 = 37;
+ public final static int FRAME_death107 = 38;
+ public final static int FRAME_drain01 = 39;
+ public final static int FRAME_drain02 = 40;
+ public final static int FRAME_drain03 = 41;
+ public final static int FRAME_drain04 = 42;
+ public final static int FRAME_drain05 = 43;
+ public final static int FRAME_drain06 = 44;
+ public final static int FRAME_drain07 = 45;
+ public final static int FRAME_drain08 = 46;
+ public final static int FRAME_drain09 = 47;
+ public final static int FRAME_drain10 = 48;
+ public final static int FRAME_drain11 = 49;
+ public final static int FRAME_drain12 = 50;
+ public final static int FRAME_drain13 = 51;
+ public final static int FRAME_drain14 = 52;
+ public final static int FRAME_drain15 = 53;
+ public final static int FRAME_drain16 = 54;
+ public final static int FRAME_drain17 = 55;
+ public final static int FRAME_drain18 = 56;
+ public final static int FRAME_pain101 = 57;
+ public final static int FRAME_pain102 = 58;
+ public final static int FRAME_pain103 = 59;
+ public final static int FRAME_pain104 = 60;
+ public final static int FRAME_pain105 = 61;
+ public final static int FRAME_pain106 = 62;
+ public final static int FRAME_pain107 = 63;
+ public final static int FRAME_pain108 = 64;
+ public final static int FRAME_pain109 = 65;
+ public final static int FRAME_pain110 = 66;
+ public final static int FRAME_pain111 = 67;
+ public final static int FRAME_run01 = 68;
+ public final static int FRAME_run02 = 69;
+ public final static int FRAME_run03 = 70;
+ public final static int FRAME_run04 = 71;
+ public final static int FRAME_run05 = 72;
+ public final static int FRAME_run06 = 73;
+ public final static int FRAME_run07 = 74;
+ public final static int FRAME_run08 = 75;
+ public final static int FRAME_run09 = 76;
+ public final static int FRAME_run10 = 77;
+ public final static int FRAME_run11 = 78;
+ public final static int FRAME_run12 = 79;
+ public final static int FRAME_run13 = 80;
+ public final static int FRAME_run14 = 81;
+ public final static int FRAME_run15 = 82;
+ public final static int FRAME_stand01 = 83;
+ public final static int FRAME_stand02 = 84;
+ public final static int FRAME_stand03 = 85;
+ public final static int FRAME_stand04 = 86;
+ public final static int FRAME_stand05 = 87;
+ public final static int FRAME_stand06 = 88;
+ public final static int FRAME_stand07 = 89;
+ public final static int FRAME_stand08 = 90;
+ public final static int FRAME_stand09 = 91;
+ public final static int FRAME_stand10 = 92;
+ public final static int FRAME_stand11 = 93;
+ public final static int FRAME_stand12 = 94;
+ public final static int FRAME_stand13 = 95;
+ public final static int FRAME_stand14 = 96;
+ public final static int FRAME_stand15 = 97;
+ public final static int FRAME_stand16 = 98;
+ public final static int FRAME_stand17 = 99;
+ public final static int FRAME_stand18 = 100;
+ public final static int FRAME_stand19 = 101;
+ public final static int FRAME_stand20 = 102;
+ public final static int FRAME_stand21 = 103;
+ public final static int FRAME_stand22 = 104;
+ public final static int FRAME_stand23 = 105;
+ public final static int FRAME_stand24 = 106;
+ public final static int FRAME_stand25 = 107;
+ public final static int FRAME_stand26 = 108;
+ public final static int FRAME_stand27 = 109;
+ public final static int FRAME_stand28 = 110;
+ public final static int FRAME_stand29 = 111;
+ public final static int FRAME_stand30 = 112;
+ public final static int FRAME_stand31 = 113;
+ public final static int FRAME_stand32 = 114;
+ public final static int FRAME_stand33 = 115;
+ public final static int FRAME_stand34 = 116;
+ public final static int FRAME_stand35 = 117;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_die;
+ static int sound_launch;
+ static int sound_impact;
+ static int sound_suck;
+ static int sound_reelin;
+ static int sound_sight;
+ static int sound_tap;
+ static int sound_scratch;
+ static int sound_search;
+
+ static EntThinkAdapter parasite_launch = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ gi.sound(self, CHAN_WEAPON, sound_launch, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_reel_in = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_reelin, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntInteractAdapter parasite_sight = new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_WEAPON, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_tap = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_tap, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_scratch = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_scratch, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_search = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_search, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+ static EntThinkAdapter parasite_start_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = parasite_move_start_walk;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = parasite_move_walk;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = parasite_move_stand;
+ return true;
+ }
+ };
+
+
+ static EntThinkAdapter parasite_end_fidget = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = parasite_move_end_fidget;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_do_fidget = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = parasite_move_fidget;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_refidget = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() <= 0.8)
+ self.monsterinfo.currentmove = parasite_move_fidget;
+ else
+ self.monsterinfo.currentmove = parasite_move_end_fidget;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_idle = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = parasite_move_start_fidget;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_start_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove = parasite_move_stand;
+ else
+ self.monsterinfo.currentmove = parasite_move_start_run;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter parasite_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove = parasite_move_stand;
+ else
+ self.monsterinfo.currentmove = parasite_move_run;
+ return true;
+ }
+ };
+ static mframe_t parasite_frames_start_fidget[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t parasite_move_start_fidget =
+ new mmove_t(FRAME_stand18, FRAME_stand21, parasite_frames_start_fidget, parasite_do_fidget);
+
+ static mframe_t parasite_frames_fidget[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, parasite_scratch),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, parasite_scratch),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t parasite_move_fidget = new mmove_t(FRAME_stand22, FRAME_stand27, parasite_frames_fidget, parasite_refidget);
+
+ static mframe_t parasite_frames_end_fidget[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, parasite_scratch),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t parasite_move_end_fidget = new mmove_t(FRAME_stand28, FRAME_stand35, parasite_frames_end_fidget, parasite_stand);
+
+
+ static mframe_t parasite_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, parasite_tap),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, parasite_tap),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, parasite_tap),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, parasite_tap),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, parasite_tap),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, parasite_tap)};
+ static mmove_t parasite_move_stand = new mmove_t(FRAME_stand01, FRAME_stand17, parasite_frames_stand, parasite_stand);
+
+ static mframe_t parasite_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 30, null),
+ new mframe_t(ai_run, 30, null),
+ new mframe_t(ai_run, 22, null),
+ new mframe_t(ai_run, 19, null),
+ new mframe_t(ai_run, 24, null),
+ new mframe_t(ai_run, 28, null),
+ new mframe_t(ai_run, 25, null)};
+ static mmove_t parasite_move_run = new mmove_t(FRAME_run03, FRAME_run09, parasite_frames_run, null);
+
+ static mframe_t parasite_frames_start_run[] = new mframe_t[] { new mframe_t(ai_run, 0, null), new mframe_t(ai_run, 30, null), };
+ static mmove_t parasite_move_start_run = new mmove_t(FRAME_run01, FRAME_run02, parasite_frames_start_run, parasite_run);
+
+ static mframe_t parasite_frames_stop_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 20, null),
+ new mframe_t(ai_run, 20, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 0, null)};
+ static mmove_t parasite_move_stop_run = new mmove_t(FRAME_run10, FRAME_run15, parasite_frames_stop_run, null);
+
+
+
+ static mframe_t parasite_frames_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 30, null),
+ new mframe_t(ai_walk, 30, null),
+ new mframe_t(ai_walk, 22, null),
+ new mframe_t(ai_walk, 19, null),
+ new mframe_t(ai_walk, 24, null),
+ new mframe_t(ai_walk, 28, null),
+ new mframe_t(ai_walk, 25, null)};
+ static mmove_t parasite_move_walk = new mmove_t(FRAME_run03, FRAME_run09, parasite_frames_walk, parasite_walk);
+
+ static mframe_t parasite_frames_start_walk[] =
+ new mframe_t[] { new mframe_t(ai_walk, 0, null), new mframe_t(ai_walk, 30, parasite_walk)};
+ static mmove_t parasite_move_start_walk = new mmove_t(FRAME_run01, FRAME_run02, parasite_frames_start_walk, null);
+
+ static mframe_t parasite_frames_stop_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 20, null),
+ new mframe_t(ai_walk, 20, null),
+ new mframe_t(ai_walk, 12, null),
+ new mframe_t(ai_walk, 10, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null)};
+ static mmove_t parasite_move_stop_walk = new mmove_t(FRAME_run10, FRAME_run15, parasite_frames_stop_walk, null);
+
+ static mframe_t parasite_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 16, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t parasite_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain111, parasite_frames_pain1, parasite_start_run);
+ static EntPainAdapter parasite_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+
+ self.monsterinfo.currentmove = parasite_move_pain1;
+ }
+ };
+
+ static boolean parasite_drain_attack_ok(float[] start, float[] end) {
+ float[] dir={0,0,0}, angles={0,0,0};
+
+ // check for max distance
+ Math3D.VectorSubtract(start, end, dir);
+ if (Math3D.VectorLength(dir) > 256)
+ return false;
+
+ // check for min/max pitch
+ Math3D.vectoangles(dir, angles);
+ if (angles[0] < -180)
+ angles[0] += 360;
+ if (Math.abs(angles[0]) > 30)
+ return false;
+
+ return true;
+ }
+ static EntThinkAdapter parasite_drain_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] offset={0,0,0}, start={0,0,0}, f={0,0,0}, r={0,0,0}, end={0,0,0}, dir={0,0,0};
+ trace_t tr;
+ int damage;
+
+ Math3D.AngleVectors(self.s.angles, f, r, null);
+ Math3D.VectorSet(offset, 24, 0, 6);
+ Math3D.G_ProjectSource(self.s.origin, offset, f, r, start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ if (!parasite_drain_attack_ok(start, end)) {
+ end[2] = self.enemy.s.origin[2] + self.enemy.maxs[2] - 8;
+ if (!parasite_drain_attack_ok(start, end)) {
+ end[2] = self.enemy.s.origin[2] + self.enemy.mins[2] + 8;
+ if (!parasite_drain_attack_ok(start, end))
+ return true;
+ }
+ }
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+
+ tr = gi.trace(start, null, null, end, self, MASK_SHOT);
+ if (tr.ent != self.enemy)
+ return true;
+
+ if (self.s.frame == FRAME_drain03) {
+ damage = 5;
+ gi.sound(self.enemy, CHAN_AUTO, sound_impact, 1, ATTN_NORM, 0);
+ } else {
+ if (self.s.frame == FRAME_drain04)
+ gi.sound(self, CHAN_WEAPON, sound_suck, 1, ATTN_NORM, 0);
+ damage = 2;
+ }
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_PARASITE_ATTACK);
+ //gi.WriteShort(self - g_edicts);
+ gi.WriteShort(self.index);
+ gi.WritePosition(start);
+ gi.WritePosition(end);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+
+ Math3D.VectorSubtract(start, end, dir);
+ T_Damage(self.enemy, self, self, dir, self.enemy.s.origin, vec3_origin, damage, 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN);
+ return true;
+ }
+ };
+
+ static mframe_t parasite_frames_drain[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, parasite_launch),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 15, parasite_drain_attack),
+ // Target hits)
+ new mframe_t(ai_charge, 0, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, 0, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, 0, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, 0, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, -2, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, -2, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, -3, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, -2, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, 0, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, -1, parasite_drain_attack), // drain)
+ new mframe_t(ai_charge, 0, parasite_reel_in), // let go)
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t parasite_move_drain = new mmove_t(FRAME_drain01, FRAME_drain18, parasite_frames_drain, parasite_start_run);
+
+ static mframe_t parasite_frames_break[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, -3, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -18, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 9, null),
+ new mframe_t(ai_charge, 6, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -18, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 8, null),
+ new mframe_t(ai_charge, 9, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -18, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ /* airborne */
+ new mframe_t(ai_charge, 0, null), /* slides */
+ new mframe_t(ai_charge, 0, null), /* slides */
+ new mframe_t(ai_charge, 0, null), /* slides */
+ new mframe_t(ai_charge, 0, null), /* slides */
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 11, null),
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, -5, null),
+ new mframe_t(ai_charge, 1, null)};
+ static mmove_t parasite_move_break = new mmove_t(FRAME_break01, FRAME_break32, parasite_frames_break, parasite_start_run);
+
+ /*
+ ===
+ Break Stuff Ends
+ ===
+ */
+
+ static EntThinkAdapter parasite_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ // if (random() <= 0.2)
+ // self.monsterinfo.currentmove = &parasite_move_break;
+ // else
+ self.monsterinfo.currentmove = parasite_move_drain;
+ return true;
+ }
+ };
+
+ /*
+ ===
+ Death Stuff Starts
+ ===
+ */
+
+ static EntThinkAdapter parasite_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink = 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t parasite_frames_death[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t parasite_move_death = new mmove_t(FRAME_death101, FRAME_death107, parasite_frames_death, parasite_dead);
+
+ static EntDieAdapter parasite_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 2; n++)
+ ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.currentmove = parasite_move_death;
+ }
+ };
+
+ /*
+ ===
+ End Death Stuff
+ ===
+ */
+
+ /*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+
+ static EntThinkAdapter SP_monster_parasite = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return true;
+ }
+
+ sound_pain1 = gi.soundindex("parasite/parpain1.wav");
+ sound_pain2 = gi.soundindex("parasite/parpain2.wav");
+ sound_die = gi.soundindex("parasite/pardeth1.wav");
+ sound_launch = gi.soundindex("parasite/paratck1.wav");
+ sound_impact = gi.soundindex("parasite/paratck2.wav");
+ sound_suck = gi.soundindex("parasite/paratck3.wav");
+ sound_reelin = gi.soundindex("parasite/paratck4.wav");
+ sound_sight = gi.soundindex("parasite/parsght1.wav");
+ sound_tap = gi.soundindex("parasite/paridle1.wav");
+ sound_scratch = gi.soundindex("parasite/paridle2.wav");
+ sound_search = gi.soundindex("parasite/parsrch1.wav");
+
+ self.s.modelindex = gi.modelindex("models/monsters/parasite/tris.md2");
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 24);
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+
+ self.health = 175;
+ self.gib_health = -50;
+ self.mass = 250;
+
+ self.pain = parasite_pain;
+ self.die = parasite_die;
+
+ self.monsterinfo.stand = parasite_stand;
+ self.monsterinfo.walk = parasite_start_walk;
+ self.monsterinfo.run = parasite_start_run;
+ self.monsterinfo.attack = parasite_attack;
+ self.monsterinfo.sight = parasite_sight;
+ self.monsterinfo.idle = parasite_idle;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = parasite_move_stand;
+ self.monsterinfo.scale = MODEL_SCALE;
+
+ walkmonster_start.think(self);
+
+ return true;
+ }
+ };
+}
diff --git a/src/jake2/game/M_Player.java b/src/jake2/game/M_Player.java
new file mode 100644
index 0000000..a9f8088
--- /dev/null
+++ b/src/jake2/game/M_Player.java
@@ -0,0 +1,230 @@
+/*
+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 11.11.2003 by RST.
+// $Id: M_Player.java,v 1.1 2004-07-07 19:59:18 hzi Exp $
+
+package jake2.game;
+
+public class M_Player extends GameWeapon {
+ // This file generated by qdata - Do NOT Modify
+
+ public final static int FRAME_stand01= 0;
+ public final static int FRAME_stand02= 1;
+ public final static int FRAME_stand03= 2;
+ public final static int FRAME_stand04= 3;
+ public final static int FRAME_stand05= 4;
+ public final static int FRAME_stand06= 5;
+ public final static int FRAME_stand07= 6;
+ public final static int FRAME_stand08= 7;
+ public final static int FRAME_stand09= 8;
+ public final static int FRAME_stand10= 9;
+ public final static int FRAME_stand11= 10;
+ public final static int FRAME_stand12= 11;
+ public final static int FRAME_stand13= 12;
+ public final static int FRAME_stand14= 13;
+ public final static int FRAME_stand15= 14;
+ public final static int FRAME_stand16= 15;
+ public final static int FRAME_stand17= 16;
+ public final static int FRAME_stand18= 17;
+ public final static int FRAME_stand19= 18;
+ public final static int FRAME_stand20= 19;
+ public final static int FRAME_stand21= 20;
+ public final static int FRAME_stand22= 21;
+ public final static int FRAME_stand23= 22;
+ public final static int FRAME_stand24= 23;
+ public final static int FRAME_stand25= 24;
+ public final static int FRAME_stand26= 25;
+ public final static int FRAME_stand27= 26;
+ public final static int FRAME_stand28= 27;
+ public final static int FRAME_stand29= 28;
+ public final static int FRAME_stand30= 29;
+ public final static int FRAME_stand31= 30;
+ public final static int FRAME_stand32= 31;
+ public final static int FRAME_stand33= 32;
+ public final static int FRAME_stand34= 33;
+ public final static int FRAME_stand35= 34;
+ public final static int FRAME_stand36= 35;
+ public final static int FRAME_stand37= 36;
+ public final static int FRAME_stand38= 37;
+ public final static int FRAME_stand39= 38;
+ public final static int FRAME_stand40= 39;
+ public final static int FRAME_run1= 40;
+ public final static int FRAME_run2= 41;
+ public final static int FRAME_run3= 42;
+ public final static int FRAME_run4= 43;
+ public final static int FRAME_run5= 44;
+ public final static int FRAME_run6= 45;
+ public final static int FRAME_attack1= 46;
+ public final static int FRAME_attack2= 47;
+ public final static int FRAME_attack3= 48;
+ public final static int FRAME_attack4= 49;
+ public final static int FRAME_attack5= 50;
+ public final static int FRAME_attack6= 51;
+ public final static int FRAME_attack7= 52;
+ public final static int FRAME_attack8= 53;
+ public final static int FRAME_pain101= 54;
+ public final static int FRAME_pain102= 55;
+ public final static int FRAME_pain103= 56;
+ public final static int FRAME_pain104= 57;
+ public final static int FRAME_pain201= 58;
+ public final static int FRAME_pain202= 59;
+ public final static int FRAME_pain203= 60;
+ public final static int FRAME_pain204= 61;
+ public final static int FRAME_pain301= 62;
+ public final static int FRAME_pain302= 63;
+ public final static int FRAME_pain303= 64;
+ public final static int FRAME_pain304= 65;
+ public final static int FRAME_jump1= 66;
+ public final static int FRAME_jump2= 67;
+ public final static int FRAME_jump3= 68;
+ public final static int FRAME_jump4= 69;
+ public final static int FRAME_jump5= 70;
+ public final static int FRAME_jump6= 71;
+ public final static int FRAME_flip01= 72;
+ public final static int FRAME_flip02= 73;
+ public final static int FRAME_flip03= 74;
+ public final static int FRAME_flip04= 75;
+ public final static int FRAME_flip05= 76;
+ public final static int FRAME_flip06= 77;
+ public final static int FRAME_flip07= 78;
+ public final static int FRAME_flip08= 79;
+ public final static int FRAME_flip09= 80;
+ public final static int FRAME_flip10= 81;
+ public final static int FRAME_flip11= 82;
+ public final static int FRAME_flip12= 83;
+ public final static int FRAME_salute01= 84;
+ public final static int FRAME_salute02= 85;
+ public final static int FRAME_salute03= 86;
+ public final static int FRAME_salute04= 87;
+ public final static int FRAME_salute05= 88;
+ public final static int FRAME_salute06= 89;
+ public final static int FRAME_salute07= 90;
+ public final static int FRAME_salute08= 91;
+ public final static int FRAME_salute09= 92;
+ public final static int FRAME_salute10= 93;
+ public final static int FRAME_salute11= 94;
+ public final static int FRAME_taunt01= 95;
+ public final static int FRAME_taunt02= 96;
+ public final static int FRAME_taunt03= 97;
+ public final static int FRAME_taunt04= 98;
+ public final static int FRAME_taunt05= 99;
+ public final static int FRAME_taunt06= 100;
+ public final static int FRAME_taunt07= 101;
+ public final static int FRAME_taunt08= 102;
+ public final static int FRAME_taunt09= 103;
+ public final static int FRAME_taunt10= 104;
+ public final static int FRAME_taunt11= 105;
+ public final static int FRAME_taunt12= 106;
+ public final static int FRAME_taunt13= 107;
+ public final static int FRAME_taunt14= 108;
+ public final static int FRAME_taunt15= 109;
+ public final static int FRAME_taunt16= 110;
+ public final static int FRAME_taunt17= 111;
+ public final static int FRAME_wave01= 112;
+ public final static int FRAME_wave02= 113;
+ public final static int FRAME_wave03= 114;
+ public final static int FRAME_wave04= 115;
+ public final static int FRAME_wave05= 116;
+ public final static int FRAME_wave06= 117;
+ public final static int FRAME_wave07= 118;
+ public final static int FRAME_wave08= 119;
+ public final static int FRAME_wave09= 120;
+ public final static int FRAME_wave10= 121;
+ public final static int FRAME_wave11= 122;
+ public final static int FRAME_point01= 123;
+ public final static int FRAME_point02= 124;
+ public final static int FRAME_point03= 125;
+ public final static int FRAME_point04= 126;
+ public final static int FRAME_point05= 127;
+ public final static int FRAME_point06= 128;
+ public final static int FRAME_point07= 129;
+ public final static int FRAME_point08= 130;
+ public final static int FRAME_point09= 131;
+ public final static int FRAME_point10= 132;
+ public final static int FRAME_point11= 133;
+ public final static int FRAME_point12= 134;
+ public final static int FRAME_crstnd01= 135;
+ public final static int FRAME_crstnd02= 136;
+ public final static int FRAME_crstnd03= 137;
+ public final static int FRAME_crstnd04= 138;
+ public final static int FRAME_crstnd05= 139;
+ public final static int FRAME_crstnd06= 140;
+ public final static int FRAME_crstnd07= 141;
+ public final static int FRAME_crstnd08= 142;
+ public final static int FRAME_crstnd09= 143;
+ public final static int FRAME_crstnd10= 144;
+ public final static int FRAME_crstnd11= 145;
+ public final static int FRAME_crstnd12= 146;
+ public final static int FRAME_crstnd13= 147;
+ public final static int FRAME_crstnd14= 148;
+ public final static int FRAME_crstnd15= 149;
+ public final static int FRAME_crstnd16= 150;
+ public final static int FRAME_crstnd17= 151;
+ public final static int FRAME_crstnd18= 152;
+ public final static int FRAME_crstnd19= 153;
+ public final static int FRAME_crwalk1= 154;
+ public final static int FRAME_crwalk2= 155;
+ public final static int FRAME_crwalk3= 156;
+ public final static int FRAME_crwalk4= 157;
+ public final static int FRAME_crwalk5= 158;
+ public final static int FRAME_crwalk6= 159;
+ public final static int FRAME_crattak1= 160;
+ public final static int FRAME_crattak2= 161;
+ public final static int FRAME_crattak3= 162;
+ public final static int FRAME_crattak4= 163;
+ public final static int FRAME_crattak5= 164;
+ public final static int FRAME_crattak6= 165;
+ public final static int FRAME_crattak7= 166;
+ public final static int FRAME_crattak8= 167;
+ public final static int FRAME_crattak9= 168;
+ public final static int FRAME_crpain1= 169;
+ public final static int FRAME_crpain2= 170;
+ public final static int FRAME_crpain3= 171;
+ public final static int FRAME_crpain4= 172;
+ public final static int FRAME_crdeath1= 173;
+ public final static int FRAME_crdeath2= 174;
+ public final static int FRAME_crdeath3= 175;
+ public final static int FRAME_crdeath4= 176;
+ public final static int FRAME_crdeath5= 177;
+ public final static int FRAME_death101= 178;
+ public final static int FRAME_death102= 179;
+ public final static int FRAME_death103= 180;
+ public final static int FRAME_death104= 181;
+ public final static int FRAME_death105= 182;
+ public final static int FRAME_death106= 183;
+ public final static int FRAME_death201= 184;
+ public final static int FRAME_death202= 185;
+ public final static int FRAME_death203= 186;
+ public final static int FRAME_death204= 187;
+ public final static int FRAME_death205= 188;
+ public final static int FRAME_death206= 189;
+ public final static int FRAME_death301= 190;
+ public final static int FRAME_death302= 191;
+ public final static int FRAME_death303= 192;
+ public final static int FRAME_death304= 193;
+ public final static int FRAME_death305= 194;
+ public final static int FRAME_death306= 195;
+ public final static int FRAME_death307= 196;
+ public final static int FRAME_death308= 197;
+
+ public final static float MODEL_SCALE= 1.000000f;
+
+}
diff --git a/src/jake2/game/M_Rider.java b/src/jake2/game/M_Rider.java
new file mode 100644
index 0000000..42966e8
--- /dev/null
+++ b/src/jake2/game/M_Rider.java
@@ -0,0 +1,29 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Rider.java,v 1.1 2004-07-07 19:59:18 hzi Exp $
+
+package jake2.game;
+
+public class M_Rider
+{
+
+}
diff --git a/src/jake2/game/M_Soldier.java b/src/jake2/game/M_Soldier.java
new file mode 100644
index 0000000..df9af8c
--- /dev/null
+++ b/src/jake2/game/M_Soldier.java
@@ -0,0 +1,1706 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Soldier.java,v 1.1 2004-07-07 19:59:19 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Soldier extends GamePWeapon {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_attak101 = 0;
+ public final static int FRAME_attak102 = 1;
+ public final static int FRAME_attak103 = 2;
+ public final static int FRAME_attak104 = 3;
+ public final static int FRAME_attak105 = 4;
+ public final static int FRAME_attak106 = 5;
+ public final static int FRAME_attak107 = 6;
+ public final static int FRAME_attak108 = 7;
+ public final static int FRAME_attak109 = 8;
+ public final static int FRAME_attak110 = 9;
+ public final static int FRAME_attak111 = 10;
+ public final static int FRAME_attak112 = 11;
+ public final static int FRAME_attak201 = 12;
+ public final static int FRAME_attak202 = 13;
+ public final static int FRAME_attak203 = 14;
+ public final static int FRAME_attak204 = 15;
+ public final static int FRAME_attak205 = 16;
+ public final static int FRAME_attak206 = 17;
+ public final static int FRAME_attak207 = 18;
+ public final static int FRAME_attak208 = 19;
+ public final static int FRAME_attak209 = 20;
+ public final static int FRAME_attak210 = 21;
+ public final static int FRAME_attak211 = 22;
+ public final static int FRAME_attak212 = 23;
+ public final static int FRAME_attak213 = 24;
+ public final static int FRAME_attak214 = 25;
+ public final static int FRAME_attak215 = 26;
+ public final static int FRAME_attak216 = 27;
+ public final static int FRAME_attak217 = 28;
+ public final static int FRAME_attak218 = 29;
+ public final static int FRAME_attak301 = 30;
+ public final static int FRAME_attak302 = 31;
+ public final static int FRAME_attak303 = 32;
+ public final static int FRAME_attak304 = 33;
+ public final static int FRAME_attak305 = 34;
+ public final static int FRAME_attak306 = 35;
+ public final static int FRAME_attak307 = 36;
+ public final static int FRAME_attak308 = 37;
+ public final static int FRAME_attak309 = 38;
+ public final static int FRAME_attak401 = 39;
+ public final static int FRAME_attak402 = 40;
+ public final static int FRAME_attak403 = 41;
+ public final static int FRAME_attak404 = 42;
+ public final static int FRAME_attak405 = 43;
+ public final static int FRAME_attak406 = 44;
+ public final static int FRAME_duck01 = 45;
+ public final static int FRAME_duck02 = 46;
+ public final static int FRAME_duck03 = 47;
+ public final static int FRAME_duck04 = 48;
+ public final static int FRAME_duck05 = 49;
+ public final static int FRAME_pain101 = 50;
+ public final static int FRAME_pain102 = 51;
+ public final static int FRAME_pain103 = 52;
+ public final static int FRAME_pain104 = 53;
+ public final static int FRAME_pain105 = 54;
+ public final static int FRAME_pain201 = 55;
+ public final static int FRAME_pain202 = 56;
+ public final static int FRAME_pain203 = 57;
+ public final static int FRAME_pain204 = 58;
+ public final static int FRAME_pain205 = 59;
+ public final static int FRAME_pain206 = 60;
+ public final static int FRAME_pain207 = 61;
+ public final static int FRAME_pain301 = 62;
+ public final static int FRAME_pain302 = 63;
+ public final static int FRAME_pain303 = 64;
+ public final static int FRAME_pain304 = 65;
+ public final static int FRAME_pain305 = 66;
+ public final static int FRAME_pain306 = 67;
+ public final static int FRAME_pain307 = 68;
+ public final static int FRAME_pain308 = 69;
+ public final static int FRAME_pain309 = 70;
+ public final static int FRAME_pain310 = 71;
+ public final static int FRAME_pain311 = 72;
+ public final static int FRAME_pain312 = 73;
+ public final static int FRAME_pain313 = 74;
+ public final static int FRAME_pain314 = 75;
+ public final static int FRAME_pain315 = 76;
+ public final static int FRAME_pain316 = 77;
+ public final static int FRAME_pain317 = 78;
+ public final static int FRAME_pain318 = 79;
+ public final static int FRAME_pain401 = 80;
+ public final static int FRAME_pain402 = 81;
+ public final static int FRAME_pain403 = 82;
+ public final static int FRAME_pain404 = 83;
+ public final static int FRAME_pain405 = 84;
+ public final static int FRAME_pain406 = 85;
+ public final static int FRAME_pain407 = 86;
+ public final static int FRAME_pain408 = 87;
+ public final static int FRAME_pain409 = 88;
+ public final static int FRAME_pain410 = 89;
+ public final static int FRAME_pain411 = 90;
+ public final static int FRAME_pain412 = 91;
+ public final static int FRAME_pain413 = 92;
+ public final static int FRAME_pain414 = 93;
+ public final static int FRAME_pain415 = 94;
+ public final static int FRAME_pain416 = 95;
+ public final static int FRAME_pain417 = 96;
+ public final static int FRAME_run01 = 97;
+ public final static int FRAME_run02 = 98;
+ public final static int FRAME_run03 = 99;
+ public final static int FRAME_run04 = 100;
+ public final static int FRAME_run05 = 101;
+ public final static int FRAME_run06 = 102;
+ public final static int FRAME_run07 = 103;
+ public final static int FRAME_run08 = 104;
+ public final static int FRAME_run09 = 105;
+ public final static int FRAME_run10 = 106;
+ public final static int FRAME_run11 = 107;
+ public final static int FRAME_run12 = 108;
+ public final static int FRAME_runs01 = 109;
+ public final static int FRAME_runs02 = 110;
+ public final static int FRAME_runs03 = 111;
+ public final static int FRAME_runs04 = 112;
+ public final static int FRAME_runs05 = 113;
+ public final static int FRAME_runs06 = 114;
+ public final static int FRAME_runs07 = 115;
+ public final static int FRAME_runs08 = 116;
+ public final static int FRAME_runs09 = 117;
+ public final static int FRAME_runs10 = 118;
+ public final static int FRAME_runs11 = 119;
+ public final static int FRAME_runs12 = 120;
+ public final static int FRAME_runs13 = 121;
+ public final static int FRAME_runs14 = 122;
+ public final static int FRAME_runs15 = 123;
+ public final static int FRAME_runs16 = 124;
+ public final static int FRAME_runs17 = 125;
+ public final static int FRAME_runs18 = 126;
+ public final static int FRAME_runt01 = 127;
+ public final static int FRAME_runt02 = 128;
+ public final static int FRAME_runt03 = 129;
+ public final static int FRAME_runt04 = 130;
+ public final static int FRAME_runt05 = 131;
+ public final static int FRAME_runt06 = 132;
+ public final static int FRAME_runt07 = 133;
+ public final static int FRAME_runt08 = 134;
+ public final static int FRAME_runt09 = 135;
+ public final static int FRAME_runt10 = 136;
+ public final static int FRAME_runt11 = 137;
+ public final static int FRAME_runt12 = 138;
+ public final static int FRAME_runt13 = 139;
+ public final static int FRAME_runt14 = 140;
+ public final static int FRAME_runt15 = 141;
+ public final static int FRAME_runt16 = 142;
+ public final static int FRAME_runt17 = 143;
+ public final static int FRAME_runt18 = 144;
+ public final static int FRAME_runt19 = 145;
+ public final static int FRAME_stand101 = 146;
+ public final static int FRAME_stand102 = 147;
+ public final static int FRAME_stand103 = 148;
+ public final static int FRAME_stand104 = 149;
+ public final static int FRAME_stand105 = 150;
+ public final static int FRAME_stand106 = 151;
+ public final static int FRAME_stand107 = 152;
+ public final static int FRAME_stand108 = 153;
+ public final static int FRAME_stand109 = 154;
+ public final static int FRAME_stand110 = 155;
+ public final static int FRAME_stand111 = 156;
+ public final static int FRAME_stand112 = 157;
+ public final static int FRAME_stand113 = 158;
+ public final static int FRAME_stand114 = 159;
+ public final static int FRAME_stand115 = 160;
+ public final static int FRAME_stand116 = 161;
+ public final static int FRAME_stand117 = 162;
+ public final static int FRAME_stand118 = 163;
+ public final static int FRAME_stand119 = 164;
+ public final static int FRAME_stand120 = 165;
+ public final static int FRAME_stand121 = 166;
+ public final static int FRAME_stand122 = 167;
+ public final static int FRAME_stand123 = 168;
+ public final static int FRAME_stand124 = 169;
+ public final static int FRAME_stand125 = 170;
+ public final static int FRAME_stand126 = 171;
+ public final static int FRAME_stand127 = 172;
+ public final static int FRAME_stand128 = 173;
+ public final static int FRAME_stand129 = 174;
+ public final static int FRAME_stand130 = 175;
+ public final static int FRAME_stand301 = 176;
+ public final static int FRAME_stand302 = 177;
+ public final static int FRAME_stand303 = 178;
+ public final static int FRAME_stand304 = 179;
+ public final static int FRAME_stand305 = 180;
+ public final static int FRAME_stand306 = 181;
+ public final static int FRAME_stand307 = 182;
+ public final static int FRAME_stand308 = 183;
+ public final static int FRAME_stand309 = 184;
+ public final static int FRAME_stand310 = 185;
+ public final static int FRAME_stand311 = 186;
+ public final static int FRAME_stand312 = 187;
+ public final static int FRAME_stand313 = 188;
+ public final static int FRAME_stand314 = 189;
+ public final static int FRAME_stand315 = 190;
+ public final static int FRAME_stand316 = 191;
+ public final static int FRAME_stand317 = 192;
+ public final static int FRAME_stand318 = 193;
+ public final static int FRAME_stand319 = 194;
+ public final static int FRAME_stand320 = 195;
+ public final static int FRAME_stand321 = 196;
+ public final static int FRAME_stand322 = 197;
+ public final static int FRAME_stand323 = 198;
+ public final static int FRAME_stand324 = 199;
+ public final static int FRAME_stand325 = 200;
+ public final static int FRAME_stand326 = 201;
+ public final static int FRAME_stand327 = 202;
+ public final static int FRAME_stand328 = 203;
+ public final static int FRAME_stand329 = 204;
+ public final static int FRAME_stand330 = 205;
+ public final static int FRAME_stand331 = 206;
+ public final static int FRAME_stand332 = 207;
+ public final static int FRAME_stand333 = 208;
+ public final static int FRAME_stand334 = 209;
+ public final static int FRAME_stand335 = 210;
+ public final static int FRAME_stand336 = 211;
+ public final static int FRAME_stand337 = 212;
+ public final static int FRAME_stand338 = 213;
+ public final static int FRAME_stand339 = 214;
+ public final static int FRAME_walk101 = 215;
+ public final static int FRAME_walk102 = 216;
+ public final static int FRAME_walk103 = 217;
+ public final static int FRAME_walk104 = 218;
+ public final static int FRAME_walk105 = 219;
+ public final static int FRAME_walk106 = 220;
+ public final static int FRAME_walk107 = 221;
+ public final static int FRAME_walk108 = 222;
+ public final static int FRAME_walk109 = 223;
+ public final static int FRAME_walk110 = 224;
+ public final static int FRAME_walk111 = 225;
+ public final static int FRAME_walk112 = 226;
+ public final static int FRAME_walk113 = 227;
+ public final static int FRAME_walk114 = 228;
+ public final static int FRAME_walk115 = 229;
+ public final static int FRAME_walk116 = 230;
+ public final static int FRAME_walk117 = 231;
+ public final static int FRAME_walk118 = 232;
+ public final static int FRAME_walk119 = 233;
+ public final static int FRAME_walk120 = 234;
+ public final static int FRAME_walk121 = 235;
+ public final static int FRAME_walk122 = 236;
+ public final static int FRAME_walk123 = 237;
+ public final static int FRAME_walk124 = 238;
+ public final static int FRAME_walk125 = 239;
+ public final static int FRAME_walk126 = 240;
+ public final static int FRAME_walk127 = 241;
+ public final static int FRAME_walk128 = 242;
+ public final static int FRAME_walk129 = 243;
+ public final static int FRAME_walk130 = 244;
+ public final static int FRAME_walk131 = 245;
+ public final static int FRAME_walk132 = 246;
+ public final static int FRAME_walk133 = 247;
+ public final static int FRAME_walk201 = 248;
+ public final static int FRAME_walk202 = 249;
+ public final static int FRAME_walk203 = 250;
+ public final static int FRAME_walk204 = 251;
+ public final static int FRAME_walk205 = 252;
+ public final static int FRAME_walk206 = 253;
+ public final static int FRAME_walk207 = 254;
+ public final static int FRAME_walk208 = 255;
+ public final static int FRAME_walk209 = 256;
+ public final static int FRAME_walk210 = 257;
+ public final static int FRAME_walk211 = 258;
+ public final static int FRAME_walk212 = 259;
+ public final static int FRAME_walk213 = 260;
+ public final static int FRAME_walk214 = 261;
+ public final static int FRAME_walk215 = 262;
+ public final static int FRAME_walk216 = 263;
+ public final static int FRAME_walk217 = 264;
+ public final static int FRAME_walk218 = 265;
+ public final static int FRAME_walk219 = 266;
+ public final static int FRAME_walk220 = 267;
+ public final static int FRAME_walk221 = 268;
+ public final static int FRAME_walk222 = 269;
+ public final static int FRAME_walk223 = 270;
+ public final static int FRAME_walk224 = 271;
+ public final static int FRAME_death101 = 272;
+ public final static int FRAME_death102 = 273;
+ public final static int FRAME_death103 = 274;
+ public final static int FRAME_death104 = 275;
+ public final static int FRAME_death105 = 276;
+ public final static int FRAME_death106 = 277;
+ public final static int FRAME_death107 = 278;
+ public final static int FRAME_death108 = 279;
+ public final static int FRAME_death109 = 280;
+ public final static int FRAME_death110 = 281;
+ public final static int FRAME_death111 = 282;
+ public final static int FRAME_death112 = 283;
+ public final static int FRAME_death113 = 284;
+ public final static int FRAME_death114 = 285;
+ public final static int FRAME_death115 = 286;
+ public final static int FRAME_death116 = 287;
+ public final static int FRAME_death117 = 288;
+ public final static int FRAME_death118 = 289;
+ public final static int FRAME_death119 = 290;
+ public final static int FRAME_death120 = 291;
+ public final static int FRAME_death121 = 292;
+ public final static int FRAME_death122 = 293;
+ public final static int FRAME_death123 = 294;
+ public final static int FRAME_death124 = 295;
+ public final static int FRAME_death125 = 296;
+ public final static int FRAME_death126 = 297;
+ public final static int FRAME_death127 = 298;
+ public final static int FRAME_death128 = 299;
+ public final static int FRAME_death129 = 300;
+ public final static int FRAME_death130 = 301;
+ public final static int FRAME_death131 = 302;
+ public final static int FRAME_death132 = 303;
+ public final static int FRAME_death133 = 304;
+ public final static int FRAME_death134 = 305;
+ public final static int FRAME_death135 = 306;
+ public final static int FRAME_death136 = 307;
+ public final static int FRAME_death201 = 308;
+ public final static int FRAME_death202 = 309;
+ public final static int FRAME_death203 = 310;
+ public final static int FRAME_death204 = 311;
+ public final static int FRAME_death205 = 312;
+ public final static int FRAME_death206 = 313;
+ public final static int FRAME_death207 = 314;
+ public final static int FRAME_death208 = 315;
+ public final static int FRAME_death209 = 316;
+ public final static int FRAME_death210 = 317;
+ public final static int FRAME_death211 = 318;
+ public final static int FRAME_death212 = 319;
+ public final static int FRAME_death213 = 320;
+ public final static int FRAME_death214 = 321;
+ public final static int FRAME_death215 = 322;
+ public final static int FRAME_death216 = 323;
+ public final static int FRAME_death217 = 324;
+ public final static int FRAME_death218 = 325;
+ public final static int FRAME_death219 = 326;
+ public final static int FRAME_death220 = 327;
+ public final static int FRAME_death221 = 328;
+ public final static int FRAME_death222 = 329;
+ public final static int FRAME_death223 = 330;
+ public final static int FRAME_death224 = 331;
+ public final static int FRAME_death225 = 332;
+ public final static int FRAME_death226 = 333;
+ public final static int FRAME_death227 = 334;
+ public final static int FRAME_death228 = 335;
+ public final static int FRAME_death229 = 336;
+ public final static int FRAME_death230 = 337;
+ public final static int FRAME_death231 = 338;
+ public final static int FRAME_death232 = 339;
+ public final static int FRAME_death233 = 340;
+ public final static int FRAME_death234 = 341;
+ public final static int FRAME_death235 = 342;
+ public final static int FRAME_death301 = 343;
+ public final static int FRAME_death302 = 344;
+ public final static int FRAME_death303 = 345;
+ public final static int FRAME_death304 = 346;
+ public final static int FRAME_death305 = 347;
+ public final static int FRAME_death306 = 348;
+ public final static int FRAME_death307 = 349;
+ public final static int FRAME_death308 = 350;
+ public final static int FRAME_death309 = 351;
+ public final static int FRAME_death310 = 352;
+ public final static int FRAME_death311 = 353;
+ public final static int FRAME_death312 = 354;
+ public final static int FRAME_death313 = 355;
+ public final static int FRAME_death314 = 356;
+ public final static int FRAME_death315 = 357;
+ public final static int FRAME_death316 = 358;
+ public final static int FRAME_death317 = 359;
+ public final static int FRAME_death318 = 360;
+ public final static int FRAME_death319 = 361;
+ public final static int FRAME_death320 = 362;
+ public final static int FRAME_death321 = 363;
+ public final static int FRAME_death322 = 364;
+ public final static int FRAME_death323 = 365;
+ public final static int FRAME_death324 = 366;
+ public final static int FRAME_death325 = 367;
+ public final static int FRAME_death326 = 368;
+ public final static int FRAME_death327 = 369;
+ public final static int FRAME_death328 = 370;
+ public final static int FRAME_death329 = 371;
+ public final static int FRAME_death330 = 372;
+ public final static int FRAME_death331 = 373;
+ public final static int FRAME_death332 = 374;
+ public final static int FRAME_death333 = 375;
+ public final static int FRAME_death334 = 376;
+ public final static int FRAME_death335 = 377;
+ public final static int FRAME_death336 = 378;
+ public final static int FRAME_death337 = 379;
+ public final static int FRAME_death338 = 380;
+ public final static int FRAME_death339 = 381;
+ public final static int FRAME_death340 = 382;
+ public final static int FRAME_death341 = 383;
+ public final static int FRAME_death342 = 384;
+ public final static int FRAME_death343 = 385;
+ public final static int FRAME_death344 = 386;
+ public final static int FRAME_death345 = 387;
+ public final static int FRAME_death401 = 388;
+ public final static int FRAME_death402 = 389;
+ public final static int FRAME_death403 = 390;
+ public final static int FRAME_death404 = 391;
+ public final static int FRAME_death405 = 392;
+ public final static int FRAME_death406 = 393;
+ public final static int FRAME_death407 = 394;
+ public final static int FRAME_death408 = 395;
+ public final static int FRAME_death409 = 396;
+ public final static int FRAME_death410 = 397;
+ public final static int FRAME_death411 = 398;
+ public final static int FRAME_death412 = 399;
+ public final static int FRAME_death413 = 400;
+ public final static int FRAME_death414 = 401;
+ public final static int FRAME_death415 = 402;
+ public final static int FRAME_death416 = 403;
+ public final static int FRAME_death417 = 404;
+ public final static int FRAME_death418 = 405;
+ public final static int FRAME_death419 = 406;
+ public final static int FRAME_death420 = 407;
+ public final static int FRAME_death421 = 408;
+ public final static int FRAME_death422 = 409;
+ public final static int FRAME_death423 = 410;
+ public final static int FRAME_death424 = 411;
+ public final static int FRAME_death425 = 412;
+ public final static int FRAME_death426 = 413;
+ public final static int FRAME_death427 = 414;
+ public final static int FRAME_death428 = 415;
+ public final static int FRAME_death429 = 416;
+ public final static int FRAME_death430 = 417;
+ public final static int FRAME_death431 = 418;
+ public final static int FRAME_death432 = 419;
+ public final static int FRAME_death433 = 420;
+ public final static int FRAME_death434 = 421;
+ public final static int FRAME_death435 = 422;
+ public final static int FRAME_death436 = 423;
+ public final static int FRAME_death437 = 424;
+ public final static int FRAME_death438 = 425;
+ public final static int FRAME_death439 = 426;
+ public final static int FRAME_death440 = 427;
+ public final static int FRAME_death441 = 428;
+ public final static int FRAME_death442 = 429;
+ public final static int FRAME_death443 = 430;
+ public final static int FRAME_death444 = 431;
+ public final static int FRAME_death445 = 432;
+ public final static int FRAME_death446 = 433;
+ public final static int FRAME_death447 = 434;
+ public final static int FRAME_death448 = 435;
+ public final static int FRAME_death449 = 436;
+ public final static int FRAME_death450 = 437;
+ public final static int FRAME_death451 = 438;
+ public final static int FRAME_death452 = 439;
+ public final static int FRAME_death453 = 440;
+ public final static int FRAME_death501 = 441;
+ public final static int FRAME_death502 = 442;
+ public final static int FRAME_death503 = 443;
+ public final static int FRAME_death504 = 444;
+ public final static int FRAME_death505 = 445;
+ public final static int FRAME_death506 = 446;
+ public final static int FRAME_death507 = 447;
+ public final static int FRAME_death508 = 448;
+ public final static int FRAME_death509 = 449;
+ public final static int FRAME_death510 = 450;
+ public final static int FRAME_death511 = 451;
+ public final static int FRAME_death512 = 452;
+ public final static int FRAME_death513 = 453;
+ public final static int FRAME_death514 = 454;
+ public final static int FRAME_death515 = 455;
+ public final static int FRAME_death516 = 456;
+ public final static int FRAME_death517 = 457;
+ public final static int FRAME_death518 = 458;
+ public final static int FRAME_death519 = 459;
+ public final static int FRAME_death520 = 460;
+ public final static int FRAME_death521 = 461;
+ public final static int FRAME_death522 = 462;
+ public final static int FRAME_death523 = 463;
+ public final static int FRAME_death524 = 464;
+ public final static int FRAME_death601 = 465;
+ public final static int FRAME_death602 = 466;
+ public final static int FRAME_death603 = 467;
+ public final static int FRAME_death604 = 468;
+ public final static int FRAME_death605 = 469;
+ public final static int FRAME_death606 = 470;
+ public final static int FRAME_death607 = 471;
+ public final static int FRAME_death608 = 472;
+ public final static int FRAME_death609 = 473;
+ public final static int FRAME_death610 = 474;
+
+ public final static float MODEL_SCALE = 1.200000f;
+
+ static int sound_idle;
+ static int sound_sight1;
+ static int sound_sight2;
+ static int sound_pain_light;
+ static int sound_pain;
+ static int sound_pain_ss;
+ static int sound_death_light;
+ static int sound_death;
+ static int sound_death_ss;
+ static int sound_cock;
+
+ static EntThinkAdapter soldier_idle = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() > 0.8)
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_cock = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.s.frame == FRAME_stand322)
+ gi.sound(self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0);
+ else
+ gi.sound(self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ // ATTACK6 (run & shoot)
+ static EntThinkAdapter soldier_fire8 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ soldier_fire(self, 7);
+ return true;
+ }
+ };
+
+
+ static EntThinkAdapter soldier_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.currentmove == soldier_move_stand3) || (Lib.random() < 0.8))
+ self.monsterinfo.currentmove = soldier_move_stand1;
+ else
+ self.monsterinfo.currentmove = soldier_move_stand3;
+ return true;
+ }
+ };
+
+ //
+ // WALK
+ //
+
+ static EntThinkAdapter soldier_walk1_random = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() > 0.1)
+ self.monsterinfo.nextframe = FRAME_walk101;
+ return true;
+ }
+ };
+
+
+ static EntThinkAdapter soldier_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() < 0.5)
+ self.monsterinfo.currentmove = soldier_move_walk1;
+ else
+ self.monsterinfo.currentmove = soldier_move_walk2;
+ return true;
+ }
+ };
+
+ // STAND
+ static mframe_t soldier_frames_stand1[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, soldier_idle),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t soldier_move_stand1 = new mmove_t(FRAME_stand101, FRAME_stand130, soldier_frames_stand1, soldier_stand);
+
+ static mframe_t soldier_frames_stand3[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, soldier_cock),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+
+ static mmove_t soldier_move_stand3 = new mmove_t(FRAME_stand301, FRAME_stand339, soldier_frames_stand3, soldier_stand);
+
+
+ static mframe_t soldier_frames_walk1[] =
+
+ new mframe_t[] {
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, -1, soldier_walk1_random),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null)};
+ static mmove_t soldier_move_walk1 = new mmove_t(FRAME_walk101, FRAME_walk133, soldier_frames_walk1, null);
+
+ static mframe_t soldier_frames_walk2[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 9, null),
+ new mframe_t(ai_walk, 8, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 1, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 7, null)};
+ static mmove_t soldier_move_walk2 = new mmove_t(FRAME_walk209, FRAME_walk218, soldier_frames_walk2, null);
+
+ static EntThinkAdapter soldier_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND)!=0) {
+ self.monsterinfo.currentmove = soldier_move_stand1;
+ return true;
+ }
+
+ if (self.monsterinfo.currentmove == soldier_move_walk1
+ || self.monsterinfo.currentmove == soldier_move_walk2
+ || self.monsterinfo.currentmove == soldier_move_start_run) {
+ self.monsterinfo.currentmove = soldier_move_run;
+ } else {
+ self.monsterinfo.currentmove = soldier_move_start_run;
+ }
+ return true;
+ }
+ };
+
+ //
+ // RUN
+ //
+
+ static mframe_t soldier_frames_start_run[] = new mframe_t[] { new mframe_t(ai_run, 7, null), new mframe_t(ai_run, 5, null)};
+ static mmove_t soldier_move_start_run = new mmove_t(FRAME_run01, FRAME_run02, soldier_frames_start_run, soldier_run);
+
+ static mframe_t soldier_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 11, null),
+ new mframe_t(ai_run, 11, null),
+ new mframe_t(ai_run, 16, null),
+ new mframe_t(ai_run, 10, null),
+ new mframe_t(ai_run, 15, null)};
+ static mmove_t soldier_move_run = new mmove_t(FRAME_run03, FRAME_run08, soldier_frames_run, null);
+
+
+
+ //
+ // PAIN
+ //
+
+ static mframe_t soldier_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t soldier_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain105, soldier_frames_pain1, soldier_run);
+
+ static mframe_t soldier_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -13, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null)};
+ static mmove_t soldier_move_pain2 = new mmove_t(FRAME_pain201, FRAME_pain207, soldier_frames_pain2, soldier_run);
+
+ static mframe_t soldier_frames_pain3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -8, null),
+ new mframe_t(ai_move, 10, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null)};
+ static mmove_t soldier_move_pain3 = new mmove_t(FRAME_pain301, FRAME_pain318, soldier_frames_pain3, soldier_run);
+
+ static mframe_t soldier_frames_pain4[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -10, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, 8, null),
+ new mframe_t(ai_move, 4, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 5, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t soldier_move_pain4 = new mmove_t(FRAME_pain401, FRAME_pain417, soldier_frames_pain4, soldier_run);
+
+ static EntPainAdapter soldier_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ float r;
+ int n;
+
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum |= 1;
+
+ if (level.time < self.pain_debounce_time) {
+ if ((self.velocity[2] > 100)
+ && ((self.monsterinfo.currentmove == soldier_move_pain1)
+ || (self.monsterinfo.currentmove == soldier_move_pain2)
+ || (self.monsterinfo.currentmove == soldier_move_pain3)))
+ self.monsterinfo.currentmove = soldier_move_pain4;
+ return;
+ }
+
+ self.pain_debounce_time = level.time + 3;
+
+ n = self.s.skinnum | 1;
+ if (n == 1)
+ gi.sound(self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0);
+ else if (n == 3)
+ gi.sound(self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0);
+
+ if (self.velocity[2] > 100) {
+ self.monsterinfo.currentmove = soldier_move_pain4;
+ return;
+ }
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ r = Lib.random();
+
+ if (r < 0.33)
+ self.monsterinfo.currentmove = soldier_move_pain1;
+ else if (r < 0.66)
+ self.monsterinfo.currentmove = soldier_move_pain2;
+ else
+ self.monsterinfo.currentmove = soldier_move_pain3;
+ }
+ };
+
+ //
+ // ATTACK
+ //
+
+ static int blaster_flash[] =
+ {
+ MZ2_SOLDIER_BLASTER_1,
+ MZ2_SOLDIER_BLASTER_2,
+ MZ2_SOLDIER_BLASTER_3,
+ MZ2_SOLDIER_BLASTER_4,
+ MZ2_SOLDIER_BLASTER_5,
+ MZ2_SOLDIER_BLASTER_6,
+ MZ2_SOLDIER_BLASTER_7,
+ MZ2_SOLDIER_BLASTER_8 };
+ static int shotgun_flash[] =
+ {
+ MZ2_SOLDIER_SHOTGUN_1,
+ MZ2_SOLDIER_SHOTGUN_2,
+ MZ2_SOLDIER_SHOTGUN_3,
+ MZ2_SOLDIER_SHOTGUN_4,
+ MZ2_SOLDIER_SHOTGUN_5,
+ MZ2_SOLDIER_SHOTGUN_6,
+ MZ2_SOLDIER_SHOTGUN_7,
+ MZ2_SOLDIER_SHOTGUN_8 };
+ static int machinegun_flash[] =
+ {
+ MZ2_SOLDIER_MACHINEGUN_1,
+ MZ2_SOLDIER_MACHINEGUN_2,
+ MZ2_SOLDIER_MACHINEGUN_3,
+ MZ2_SOLDIER_MACHINEGUN_4,
+ MZ2_SOLDIER_MACHINEGUN_5,
+ MZ2_SOLDIER_MACHINEGUN_6,
+ MZ2_SOLDIER_MACHINEGUN_7,
+ MZ2_SOLDIER_MACHINEGUN_8 };
+
+ static void soldier_fire(edict_t self, int flash_number) {
+ float[] start={0,0,0};
+ float[] forward={0,0,0}, right={0,0,0}, up={0,0,0};
+ float[] aim={0,0,0};
+ float[] dir={0,0,0};
+ float[] end={0,0,0};
+ float r, u;
+ int flash_index;
+
+ if (self.s.skinnum < 2)
+ flash_index = blaster_flash[flash_number];
+ else if (self.s.skinnum < 4)
+ flash_index = shotgun_flash[flash_number];
+ else
+ flash_index = machinegun_flash[flash_number];
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_index], forward, right, start);
+
+ if (flash_number == 5 || flash_number == 6) {
+ Math3D.VectorCopy(forward, aim);
+ } else {
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ end[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(end, start, aim);
+ Math3D.vectoangles(aim, dir);
+ Math3D.AngleVectors(dir, forward, right, up);
+
+ r = Lib.crandom() * 1000;
+ u = Lib.crandom() * 500;
+ Math3D.VectorMA(start, 8192, forward, end);
+ Math3D.VectorMA(end, r, right, end);
+ Math3D.VectorMA(end, u, up, end);
+
+ Math3D.VectorSubtract(end, start, aim);
+ Math3D.VectorNormalize(aim);
+ }
+
+ if (self.s.skinnum <= 1) {
+ Monster.monster_fire_blaster(self, start, aim, 5, 600, flash_index, EF_BLASTER);
+ } else if (self.s.skinnum <= 3) {
+ Monster.monster_fire_shotgun(
+ self,
+ start,
+ aim,
+ 2,
+ 1,
+ DEFAULT_SHOTGUN_HSPREAD,
+ DEFAULT_SHOTGUN_VSPREAD,
+ DEFAULT_SHOTGUN_COUNT,
+ flash_index);
+ } else {
+ if (0 == (self.monsterinfo.aiflags & AI_HOLD_FRAME))
+ self.monsterinfo.pausetime = level.time + (3 + Lib.rand() % 8) * FRAMETIME;
+
+ Monster.monster_fire_bullet(self, start, aim, 2, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_index);
+
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ }
+ }
+
+ // ATTACK1 (blaster/shotgun)
+
+ static EntThinkAdapter soldier_fire1 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ soldier_fire(self, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_attack1_refire1 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.s.skinnum > 1)
+ return true;
+
+ if (self.enemy.health <= 0)
+ return true;
+
+ if (((skill.value == 3) && (Lib.random() < 0.5)) || (range(self, self.enemy) == RANGE_MELEE))
+ self.monsterinfo.nextframe = FRAME_attak102;
+ else
+ self.monsterinfo.nextframe = FRAME_attak110;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_attack1_refire2 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.s.skinnum < 2)
+ return true;
+
+ if (self.enemy.health <= 0)
+ return true;
+
+ if (((skill.value == 3) && (Lib.random() < 0.5)) || (range(self, self.enemy) == RANGE_MELEE))
+ self.monsterinfo.nextframe = FRAME_attak102;
+ return true;
+ }
+ };
+
+ static mframe_t soldier_frames_attack1[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_fire1),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_attack1_refire1),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_cock),
+ new mframe_t(ai_charge, 0, soldier_attack1_refire2),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t soldier_move_attack1 = new mmove_t(FRAME_attak101, FRAME_attak112, soldier_frames_attack1, soldier_run);
+
+ // ATTACK2 (blaster/shotgun)
+
+ static EntThinkAdapter soldier_fire2 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ soldier_fire(self, 1);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_attack2_refire1 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.s.skinnum > 1)
+ return true;
+
+ if (self.enemy.health <= 0)
+ return true;
+
+ if (((skill.value == 3) && (Lib.random() < 0.5)) || (range(self, self.enemy) == RANGE_MELEE))
+ self.monsterinfo.nextframe = FRAME_attak204;
+ else
+ self.monsterinfo.nextframe = FRAME_attak216;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_attack2_refire2 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.s.skinnum < 2)
+ return true;
+
+ if (self.enemy.health <= 0)
+ return true ;
+
+ if (((skill.value == 3) && (Lib.random() < 0.5)) || (range(self, self.enemy) == RANGE_MELEE))
+ self.monsterinfo.nextframe = FRAME_attak204;
+ return true;
+ }
+ };
+
+ static mframe_t soldier_frames_attack2[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_fire2),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_attack2_refire1),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_cock),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_attack2_refire2),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t soldier_move_attack2 = new mmove_t(FRAME_attak201, FRAME_attak218, soldier_frames_attack2, soldier_run);
+
+ // ATTACK3 (duck and shoot)
+
+ static EntThinkAdapter soldier_duck_down = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_DUCKED)!=0)
+ return true;
+ self.monsterinfo.aiflags |= AI_DUCKED;
+ self.maxs[2] -= 32;
+ self.takedamage = DAMAGE_YES;
+ self.monsterinfo.pausetime = level.time + 1;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_duck_up = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.aiflags &= ~AI_DUCKED;
+ self.maxs[2] += 32;
+ self.takedamage = DAMAGE_AIM;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_fire3 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ soldier_duck_down.think(self);
+ soldier_fire(self, 2);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_attack3_refire = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((level.time + 0.4) < self.monsterinfo.pausetime)
+ self.monsterinfo.nextframe = FRAME_attak303;
+ return true;
+ }
+ };
+
+ static mframe_t soldier_frames_attack3[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_fire3),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_attack3_refire),
+ new mframe_t(ai_charge, 0, soldier_duck_up),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t soldier_move_attack3 = new mmove_t(FRAME_attak301, FRAME_attak309, soldier_frames_attack3, soldier_run);
+
+ // ATTACK4 (machinegun)
+
+ static EntThinkAdapter soldier_fire4 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ soldier_fire(self, 3);
+ //
+ // if (self.enemy.health <= 0)
+ // return;
+ //
+ // if ( ((skill.value == 3) && (random() < 0.5)) || (range(self, self.enemy) == RANGE_MELEE) )
+ // self.monsterinfo.nextframe = FRAME_attak402;
+ return true;
+ }
+ };
+
+ static mframe_t soldier_frames_attack4[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, soldier_fire4),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+ static mmove_t soldier_move_attack4 = new mmove_t(FRAME_attak401, FRAME_attak406, soldier_frames_attack4, soldier_run);
+
+
+
+ static EntThinkAdapter soldier_attack6_refire = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.enemy.health <= 0)
+ return true;
+
+ if (range(self, self.enemy) < RANGE_MID)
+ return true;
+
+ if (skill.value == 3)
+ self.monsterinfo.nextframe = FRAME_runs03;
+ return true;
+ }
+ };
+
+ static mframe_t soldier_frames_attack6[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 10, null),
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 12, null),
+ new mframe_t(ai_charge, 11, soldier_fire8),
+ new mframe_t(ai_charge, 13, null),
+ new mframe_t(ai_charge, 18, null),
+ new mframe_t(ai_charge, 15, null),
+ new mframe_t(ai_charge, 14, null),
+ new mframe_t(ai_charge, 11, null),
+ new mframe_t(ai_charge, 8, null),
+ new mframe_t(ai_charge, 11, null),
+ new mframe_t(ai_charge, 12, null),
+ new mframe_t(ai_charge, 12, null),
+ new mframe_t(ai_charge, 17, soldier_attack6_refire)};
+ static mmove_t soldier_move_attack6 = new mmove_t(FRAME_runs01, FRAME_runs14, soldier_frames_attack6, soldier_run);
+
+ static EntThinkAdapter soldier_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.s.skinnum < 4) {
+ if (Lib.random() < 0.5)
+ self.monsterinfo.currentmove = soldier_move_attack1;
+ else
+ self.monsterinfo.currentmove = soldier_move_attack2;
+ } else {
+ self.monsterinfo.currentmove = soldier_move_attack4;
+ }
+ return true;
+ }
+ };
+
+ //
+ // SIGHT
+ //
+
+ static EntInteractAdapter soldier_sight = new EntInteractAdapter() {
+ public boolean interact(edict_t self, edict_t other) {
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0);
+
+ if ((skill.value > 0) && (range(self, self.enemy) >= RANGE_MID)) {
+ if (Lib.random() > 0.5)
+ self.monsterinfo.currentmove = soldier_move_attack6;
+ }
+ return true;
+ }
+ };
+
+ //
+ // DUCK
+ //
+
+ static EntThinkAdapter soldier_duck_hold = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (level.time >= self.monsterinfo.pausetime)
+ self.monsterinfo.aiflags &= ~AI_HOLD_FRAME;
+ else
+ self.monsterinfo.aiflags |= AI_HOLD_FRAME;
+ return true;
+ }
+ };
+
+ static mframe_t soldier_frames_duck[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 5, soldier_duck_down),
+ new mframe_t(ai_move, -1, soldier_duck_hold),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 0, soldier_duck_up),
+ new mframe_t(ai_move, 5, null)};
+ static mmove_t soldier_move_duck = new mmove_t(FRAME_duck01, FRAME_duck05, soldier_frames_duck, soldier_run);
+
+ static EntDodgeAdapter soldier_dodge = new EntDodgeAdapter() {
+ public void dodge(edict_t self, edict_t attacker, float eta) {
+ float r;
+
+ r = Lib.random();
+ if (r > 0.25)
+ return;
+
+ if (self.enemy== null)
+ self.enemy = attacker;
+
+ if (skill.value == 0) {
+ self.monsterinfo.currentmove = soldier_move_duck;
+ return;
+ }
+
+ self.monsterinfo.pausetime = level.time + eta + 0.3f;
+ r = Lib.random();
+
+ if (skill.value == 1) {
+ if (r > 0.33)
+ self.monsterinfo.currentmove = soldier_move_duck;
+ else
+ self.monsterinfo.currentmove = soldier_move_attack3;
+ return;
+ }
+
+ if (skill.value >= 2) {
+ if (r > 0.66)
+ self.monsterinfo.currentmove = soldier_move_duck;
+ else
+ self.monsterinfo.currentmove = soldier_move_attack3;
+ return;
+ }
+
+ self.monsterinfo.currentmove = soldier_move_attack3;
+ }
+ };
+
+ //
+ // DEATH
+ //
+
+ static EntThinkAdapter soldier_fire6 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ soldier_fire(self, 5);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_fire7 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ soldier_fire(self, 6);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter soldier_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, -8);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink = 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t soldier_frames_death1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -10, null),
+ new mframe_t(ai_move, -10, null),
+ new mframe_t(ai_move, -10, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, soldier_fire6),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, soldier_fire7),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t soldier_move_death1 = new mmove_t(FRAME_death101, FRAME_death136, soldier_frames_death1, soldier_dead);
+
+ static mframe_t soldier_frames_death2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t soldier_move_death2 = new mmove_t(FRAME_death201, FRAME_death235, soldier_frames_death2, soldier_dead);
+
+ static mframe_t soldier_frames_death3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ };
+ static mmove_t soldier_move_death3 = new mmove_t(FRAME_death301, FRAME_death345, soldier_frames_death3, soldier_dead);
+
+ static mframe_t soldier_frames_death4[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t soldier_move_death4 = new mmove_t(FRAME_death401, FRAME_death453, soldier_frames_death4, soldier_dead);
+
+ static mframe_t soldier_frames_death5[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t soldier_move_death5 = new mmove_t(FRAME_death501, FRAME_death524, soldier_frames_death5, soldier_dead);
+
+ static mframe_t soldier_frames_death6[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t soldier_move_death6 = new mmove_t(FRAME_death601, FRAME_death610, soldier_frames_death6, soldier_dead);
+
+ static EntDieAdapter soldier_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 3; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ ThrowGib(self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+ self.s.skinnum |= 1;
+
+ if (self.s.skinnum == 1)
+ gi.sound(self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0);
+ else if (self.s.skinnum == 3)
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+ else // (self.s.skinnum == 5)
+ gi.sound(self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0);
+
+ if (Math.abs((self.s.origin[2] + self.viewheight) - point[2]) <= 4) {
+ // head shot
+ self.monsterinfo.currentmove = soldier_move_death3;
+ return;
+ }
+
+ n = Lib.rand() % 5;
+ if (n == 0)
+ self.monsterinfo.currentmove = soldier_move_death1;
+ else if (n == 1)
+ self.monsterinfo.currentmove = soldier_move_death2;
+ else if (n == 2)
+ self.monsterinfo.currentmove = soldier_move_death4;
+ else if (n == 3)
+ self.monsterinfo.currentmove = soldier_move_death5;
+ else
+ self.monsterinfo.currentmove = soldier_move_death6;
+ }
+ };
+
+ //
+ // SPAWN
+ //
+
+ static EntThinkAdapter SP_monster_soldier_x = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.s.modelindex = gi.modelindex("models/monsters/soldier/tris.md2");
+ self.monsterinfo.scale = MODEL_SCALE;
+ Math3D.VectorSet(self.mins, -16, -16, -24);
+ Math3D.VectorSet(self.maxs, 16, 16, 32);
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+
+ sound_idle = gi.soundindex("soldier/solidle1.wav");
+ sound_sight1 = gi.soundindex("soldier/solsght1.wav");
+ sound_sight2 = gi.soundindex("soldier/solsrch1.wav");
+ sound_cock = gi.soundindex("infantry/infatck3.wav");
+
+ self.mass = 100;
+
+ self.pain = soldier_pain;
+ self.die = soldier_die;
+
+ self.monsterinfo.stand = soldier_stand;
+ self.monsterinfo.walk = soldier_walk;
+ self.monsterinfo.run = soldier_run;
+ self.monsterinfo.dodge = soldier_dodge;
+ self.monsterinfo.attack = soldier_attack;
+ self.monsterinfo.melee = null;
+ self.monsterinfo.sight = soldier_sight;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.stand.think(self);
+
+ walkmonster_start.think(self);
+ return true;
+ }
+ };
+
+ /*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static EntThinkAdapter SP_monster_soldier_light = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (deathmatch.value!=0) {
+ G_FreeEdict(self);
+ return true;
+ }
+
+ SP_monster_soldier_x.think(self);
+
+ sound_pain_light = gi.soundindex("soldier/solpain2.wav");
+ sound_death_light = gi.soundindex("soldier/soldeth2.wav");
+ gi.modelindex("models/objects/laser/tris.md2");
+ gi.soundindex("misc/lasfly.wav");
+ gi.soundindex("soldier/solatck2.wav");
+
+ self.s.skinnum = 0;
+ self.health = 20;
+ self.gib_health = -30;
+ return true;
+ }
+ };
+
+ /*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+
+ static EntThinkAdapter SP_monster_soldier = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (deathmatch.value!=0) {
+ G_FreeEdict(self);
+ return true;
+ }
+
+ SP_monster_soldier_x.think(self);
+
+ sound_pain = gi.soundindex("soldier/solpain1.wav");
+ sound_death = gi.soundindex("soldier/soldeth1.wav");
+ gi.soundindex("soldier/solatck1.wav");
+
+ self.s.skinnum = 2;
+ self.health = 30;
+ self.gib_health = -30;
+ return true;
+ }
+ };
+
+ /*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
+ */
+ static EntThinkAdapter SP_monster_soldier_ss = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return true;
+ }
+
+ SP_monster_soldier_x.think(self);
+
+ sound_pain_ss = gi.soundindex("soldier/solpain3.wav");
+ sound_death_ss = gi.soundindex("soldier/soldeth3.wav");
+ gi.soundindex("soldier/solatck3.wav");
+
+ self.s.skinnum = 4;
+ self.health = 40;
+ self.gib_health = -30;
+ return true;
+ }
+ };
+
+}
diff --git a/src/jake2/game/M_Supertank.java b/src/jake2/game/M_Supertank.java
new file mode 100644
index 0000000..a70d8f2
--- /dev/null
+++ b/src/jake2/game/M_Supertank.java
@@ -0,0 +1,964 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Supertank.java,v 1.1 2004-07-07 19:59:19 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Supertank extends GamePWeapon {
+
+ // This file generated by ModelGen - Do NOT Modify
+
+ public final static int FRAME_attak1_1 = 0;
+ public final static int FRAME_attak1_2 = 1;
+ public final static int FRAME_attak1_3 = 2;
+ public final static int FRAME_attak1_4 = 3;
+ public final static int FRAME_attak1_5 = 4;
+ public final static int FRAME_attak1_6 = 5;
+ public final static int FRAME_attak1_7 = 6;
+ public final static int FRAME_attak1_8 = 7;
+ public final static int FRAME_attak1_9 = 8;
+ public final static int FRAME_attak1_10 = 9;
+ public final static int FRAME_attak1_11 = 10;
+ public final static int FRAME_attak1_12 = 11;
+ public final static int FRAME_attak1_13 = 12;
+ public final static int FRAME_attak1_14 = 13;
+ public final static int FRAME_attak1_15 = 14;
+ public final static int FRAME_attak1_16 = 15;
+ public final static int FRAME_attak1_17 = 16;
+ public final static int FRAME_attak1_18 = 17;
+ public final static int FRAME_attak1_19 = 18;
+ public final static int FRAME_attak1_20 = 19;
+ public final static int FRAME_attak2_1 = 20;
+ public final static int FRAME_attak2_2 = 21;
+ public final static int FRAME_attak2_3 = 22;
+ public final static int FRAME_attak2_4 = 23;
+ public final static int FRAME_attak2_5 = 24;
+ public final static int FRAME_attak2_6 = 25;
+ public final static int FRAME_attak2_7 = 26;
+ public final static int FRAME_attak2_8 = 27;
+ public final static int FRAME_attak2_9 = 28;
+ public final static int FRAME_attak2_10 = 29;
+ public final static int FRAME_attak2_11 = 30;
+ public final static int FRAME_attak2_12 = 31;
+ public final static int FRAME_attak2_13 = 32;
+ public final static int FRAME_attak2_14 = 33;
+ public final static int FRAME_attak2_15 = 34;
+ public final static int FRAME_attak2_16 = 35;
+ public final static int FRAME_attak2_17 = 36;
+ public final static int FRAME_attak2_18 = 37;
+ public final static int FRAME_attak2_19 = 38;
+ public final static int FRAME_attak2_20 = 39;
+ public final static int FRAME_attak2_21 = 40;
+ public final static int FRAME_attak2_22 = 41;
+ public final static int FRAME_attak2_23 = 42;
+ public final static int FRAME_attak2_24 = 43;
+ public final static int FRAME_attak2_25 = 44;
+ public final static int FRAME_attak2_26 = 45;
+ public final static int FRAME_attak2_27 = 46;
+ public final static int FRAME_attak3_1 = 47;
+ public final static int FRAME_attak3_2 = 48;
+ public final static int FRAME_attak3_3 = 49;
+ public final static int FRAME_attak3_4 = 50;
+ public final static int FRAME_attak3_5 = 51;
+ public final static int FRAME_attak3_6 = 52;
+ public final static int FRAME_attak3_7 = 53;
+ public final static int FRAME_attak3_8 = 54;
+ public final static int FRAME_attak3_9 = 55;
+ public final static int FRAME_attak3_10 = 56;
+ public final static int FRAME_attak3_11 = 57;
+ public final static int FRAME_attak3_12 = 58;
+ public final static int FRAME_attak3_13 = 59;
+ public final static int FRAME_attak3_14 = 60;
+ public final static int FRAME_attak3_15 = 61;
+ public final static int FRAME_attak3_16 = 62;
+ public final static int FRAME_attak3_17 = 63;
+ public final static int FRAME_attak3_18 = 64;
+ public final static int FRAME_attak3_19 = 65;
+ public final static int FRAME_attak3_20 = 66;
+ public final static int FRAME_attak3_21 = 67;
+ public final static int FRAME_attak3_22 = 68;
+ public final static int FRAME_attak3_23 = 69;
+ public final static int FRAME_attak3_24 = 70;
+ public final static int FRAME_attak3_25 = 71;
+ public final static int FRAME_attak3_26 = 72;
+ public final static int FRAME_attak3_27 = 73;
+ public final static int FRAME_attak4_1 = 74;
+ public final static int FRAME_attak4_2 = 75;
+ public final static int FRAME_attak4_3 = 76;
+ public final static int FRAME_attak4_4 = 77;
+ public final static int FRAME_attak4_5 = 78;
+ public final static int FRAME_attak4_6 = 79;
+ public final static int FRAME_backwd_1 = 80;
+ public final static int FRAME_backwd_2 = 81;
+ public final static int FRAME_backwd_3 = 82;
+ public final static int FRAME_backwd_4 = 83;
+ public final static int FRAME_backwd_5 = 84;
+ public final static int FRAME_backwd_6 = 85;
+ public final static int FRAME_backwd_7 = 86;
+ public final static int FRAME_backwd_8 = 87;
+ public final static int FRAME_backwd_9 = 88;
+ public final static int FRAME_backwd_10 = 89;
+ public final static int FRAME_backwd_11 = 90;
+ public final static int FRAME_backwd_12 = 91;
+ public final static int FRAME_backwd_13 = 92;
+ public final static int FRAME_backwd_14 = 93;
+ public final static int FRAME_backwd_15 = 94;
+ public final static int FRAME_backwd_16 = 95;
+ public final static int FRAME_backwd_17 = 96;
+ public final static int FRAME_backwd_18 = 97;
+ public final static int FRAME_death_1 = 98;
+ public final static int FRAME_death_2 = 99;
+ public final static int FRAME_death_3 = 100;
+ public final static int FRAME_death_4 = 101;
+ public final static int FRAME_death_5 = 102;
+ public final static int FRAME_death_6 = 103;
+ public final static int FRAME_death_7 = 104;
+ public final static int FRAME_death_8 = 105;
+ public final static int FRAME_death_9 = 106;
+ public final static int FRAME_death_10 = 107;
+ public final static int FRAME_death_11 = 108;
+ public final static int FRAME_death_12 = 109;
+ public final static int FRAME_death_13 = 110;
+ public final static int FRAME_death_14 = 111;
+ public final static int FRAME_death_15 = 112;
+ public final static int FRAME_death_16 = 113;
+ public final static int FRAME_death_17 = 114;
+ public final static int FRAME_death_18 = 115;
+ public final static int FRAME_death_19 = 116;
+ public final static int FRAME_death_20 = 117;
+ public final static int FRAME_death_21 = 118;
+ public final static int FRAME_death_22 = 119;
+ public final static int FRAME_death_23 = 120;
+ public final static int FRAME_death_24 = 121;
+ public final static int FRAME_death_31 = 122;
+ public final static int FRAME_death_32 = 123;
+ public final static int FRAME_death_33 = 124;
+ public final static int FRAME_death_45 = 125;
+ public final static int FRAME_death_46 = 126;
+ public final static int FRAME_death_47 = 127;
+ public final static int FRAME_forwrd_1 = 128;
+ public final static int FRAME_forwrd_2 = 129;
+ public final static int FRAME_forwrd_3 = 130;
+ public final static int FRAME_forwrd_4 = 131;
+ public final static int FRAME_forwrd_5 = 132;
+ public final static int FRAME_forwrd_6 = 133;
+ public final static int FRAME_forwrd_7 = 134;
+ public final static int FRAME_forwrd_8 = 135;
+ public final static int FRAME_forwrd_9 = 136;
+ public final static int FRAME_forwrd_10 = 137;
+ public final static int FRAME_forwrd_11 = 138;
+ public final static int FRAME_forwrd_12 = 139;
+ public final static int FRAME_forwrd_13 = 140;
+ public final static int FRAME_forwrd_14 = 141;
+ public final static int FRAME_forwrd_15 = 142;
+ public final static int FRAME_forwrd_16 = 143;
+ public final static int FRAME_forwrd_17 = 144;
+ public final static int FRAME_forwrd_18 = 145;
+ public final static int FRAME_left_1 = 146;
+ public final static int FRAME_left_2 = 147;
+ public final static int FRAME_left_3 = 148;
+ public final static int FRAME_left_4 = 149;
+ public final static int FRAME_left_5 = 150;
+ public final static int FRAME_left_6 = 151;
+ public final static int FRAME_left_7 = 152;
+ public final static int FRAME_left_8 = 153;
+ public final static int FRAME_left_9 = 154;
+ public final static int FRAME_left_10 = 155;
+ public final static int FRAME_left_11 = 156;
+ public final static int FRAME_left_12 = 157;
+ public final static int FRAME_left_13 = 158;
+ public final static int FRAME_left_14 = 159;
+ public final static int FRAME_left_15 = 160;
+ public final static int FRAME_left_16 = 161;
+ public final static int FRAME_left_17 = 162;
+ public final static int FRAME_left_18 = 163;
+ public final static int FRAME_pain1_1 = 164;
+ public final static int FRAME_pain1_2 = 165;
+ public final static int FRAME_pain1_3 = 166;
+ public final static int FRAME_pain1_4 = 167;
+ public final static int FRAME_pain2_5 = 168;
+ public final static int FRAME_pain2_6 = 169;
+ public final static int FRAME_pain2_7 = 170;
+ public final static int FRAME_pain2_8 = 171;
+ public final static int FRAME_pain3_9 = 172;
+ public final static int FRAME_pain3_10 = 173;
+ public final static int FRAME_pain3_11 = 174;
+ public final static int FRAME_pain3_12 = 175;
+ public final static int FRAME_right_1 = 176;
+ public final static int FRAME_right_2 = 177;
+ public final static int FRAME_right_3 = 178;
+ public final static int FRAME_right_4 = 179;
+ public final static int FRAME_right_5 = 180;
+ public final static int FRAME_right_6 = 181;
+ public final static int FRAME_right_7 = 182;
+ public final static int FRAME_right_8 = 183;
+ public final static int FRAME_right_9 = 184;
+ public final static int FRAME_right_10 = 185;
+ public final static int FRAME_right_11 = 186;
+ public final static int FRAME_right_12 = 187;
+ public final static int FRAME_right_13 = 188;
+ public final static int FRAME_right_14 = 189;
+ public final static int FRAME_right_15 = 190;
+ public final static int FRAME_right_16 = 191;
+ public final static int FRAME_right_17 = 192;
+ public final static int FRAME_right_18 = 193;
+ public final static int FRAME_stand_1 = 194;
+ public final static int FRAME_stand_2 = 195;
+ public final static int FRAME_stand_3 = 196;
+ public final static int FRAME_stand_4 = 197;
+ public final static int FRAME_stand_5 = 198;
+ public final static int FRAME_stand_6 = 199;
+ public final static int FRAME_stand_7 = 200;
+ public final static int FRAME_stand_8 = 201;
+ public final static int FRAME_stand_9 = 202;
+ public final static int FRAME_stand_10 = 203;
+ public final static int FRAME_stand_11 = 204;
+ public final static int FRAME_stand_12 = 205;
+ public final static int FRAME_stand_13 = 206;
+ public final static int FRAME_stand_14 = 207;
+ public final static int FRAME_stand_15 = 208;
+ public final static int FRAME_stand_16 = 209;
+ public final static int FRAME_stand_17 = 210;
+ public final static int FRAME_stand_18 = 211;
+ public final static int FRAME_stand_19 = 212;
+ public final static int FRAME_stand_20 = 213;
+ public final static int FRAME_stand_21 = 214;
+ public final static int FRAME_stand_22 = 215;
+ public final static int FRAME_stand_23 = 216;
+ public final static int FRAME_stand_24 = 217;
+ public final static int FRAME_stand_25 = 218;
+ public final static int FRAME_stand_26 = 219;
+ public final static int FRAME_stand_27 = 220;
+ public final static int FRAME_stand_28 = 221;
+ public final static int FRAME_stand_29 = 222;
+ public final static int FRAME_stand_30 = 223;
+ public final static int FRAME_stand_31 = 224;
+ public final static int FRAME_stand_32 = 225;
+ public final static int FRAME_stand_33 = 226;
+ public final static int FRAME_stand_34 = 227;
+ public final static int FRAME_stand_35 = 228;
+ public final static int FRAME_stand_36 = 229;
+ public final static int FRAME_stand_37 = 230;
+ public final static int FRAME_stand_38 = 231;
+ public final static int FRAME_stand_39 = 232;
+ public final static int FRAME_stand_40 = 233;
+ public final static int FRAME_stand_41 = 234;
+ public final static int FRAME_stand_42 = 235;
+ public final static int FRAME_stand_43 = 236;
+ public final static int FRAME_stand_44 = 237;
+ public final static int FRAME_stand_45 = 238;
+ public final static int FRAME_stand_46 = 239;
+ public final static int FRAME_stand_47 = 240;
+ public final static int FRAME_stand_48 = 241;
+ public final static int FRAME_stand_49 = 242;
+ public final static int FRAME_stand_50 = 243;
+ public final static int FRAME_stand_51 = 244;
+ public final static int FRAME_stand_52 = 245;
+ public final static int FRAME_stand_53 = 246;
+ public final static int FRAME_stand_54 = 247;
+ public final static int FRAME_stand_55 = 248;
+ public final static int FRAME_stand_56 = 249;
+ public final static int FRAME_stand_57 = 250;
+ public final static int FRAME_stand_58 = 251;
+ public final static int FRAME_stand_59 = 252;
+ public final static int FRAME_stand_60 = 253;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_pain1;
+ static int sound_pain2;
+ static int sound_pain3;
+ static int sound_death;
+ static int sound_search1;
+ static int sound_search2;
+
+ static int tread_sound;
+
+ static EntThinkAdapter TreadSound = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, tread_sound, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter supertank_search = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (Lib.random() < 0.5)
+ gi.sound(self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
+ else
+ gi.sound(self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ //
+ // stand
+ //
+
+ static mframe_t supertank_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t supertank_move_stand = new mmove_t(FRAME_stand_1, FRAME_stand_60, supertank_frames_stand, null);
+
+ static EntThinkAdapter supertank_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = supertank_move_stand;
+ return true;
+ }
+ };
+
+
+
+ static mframe_t supertank_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 12, TreadSound),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null),
+ new mframe_t(ai_run, 12, null)};
+ static mmove_t supertank_move_run = new mmove_t(FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_run, null);
+
+ //
+ // walk
+ //
+
+ static mframe_t supertank_frames_forward[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 4, TreadSound),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, null)};
+ static mmove_t supertank_move_forward = new mmove_t(FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_forward, null);
+
+ static EntThinkAdapter supertank_forward = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = supertank_move_forward;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter supertank_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = supertank_move_forward;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter supertank_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0)
+ self.monsterinfo.currentmove = supertank_move_stand;
+ else
+ self.monsterinfo.currentmove = supertank_move_run;
+ return true;
+ }
+ };
+
+ //
+ // death
+ //
+ static EntThinkAdapter supertank_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -60, -60, 0);
+ Math3D.VectorSet(self.maxs, 60, 60, 72);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink = 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter supertankRocket = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward={0,0,0}, right={0,0,0};
+ float[] start={0,0,0};
+ float[] dir={0,0,0};
+ float[] vec={0,0,0};
+ int flash_number;
+
+ if (self.s.frame == FRAME_attak2_8)
+ flash_number = MZ2_SUPERTANK_ROCKET_1;
+ else if (self.s.frame == FRAME_attak2_11)
+ flash_number = MZ2_SUPERTANK_ROCKET_2;
+ else // (self.s.frame == FRAME_attak2_14)
+ flash_number = MZ2_SUPERTANK_ROCKET_3;
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+
+ Monster.monster_fire_rocket(self, start, dir, 50, 500, flash_number);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter supertankMachineGun = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] dir={0,0,0};
+ float[] vec={0,0,0};
+ float[] start={0,0,0};
+ float[] forward={0,0,0}, right={0,0,0};
+ int flash_number;
+
+ flash_number = MZ2_SUPERTANK_MACHINEGUN_1 + (self.s.frame - FRAME_attak1_1);
+
+ //FIXME!!!
+ dir[0] = 0;
+ dir[1] = self.s.angles[1];
+ dir[2] = 0;
+
+ Math3D.AngleVectors(dir, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ if (self.enemy != null) {
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ Math3D.VectorMA(vec, 0, self.enemy.velocity, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, forward);
+ Math3D.VectorNormalize(forward);
+ }
+
+ Monster.monster_fire_bullet(self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter supertank_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] vec={0,0,0};
+ float range;
+ //float r;
+
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, vec);
+ range = Math3D.VectorLength(vec);
+
+ //r = random();
+
+ // Attack 1 == Chaingun
+ // Attack 2 == Rocket Launcher
+
+ if (range <= 160) {
+ self.monsterinfo.currentmove = supertank_move_attack1;
+ } else { // fire rockets more often at distance
+ if (Lib.random() < 0.3)
+ self.monsterinfo.currentmove = supertank_move_attack1;
+ else
+ self.monsterinfo.currentmove = supertank_move_attack2;
+ }
+ return true;
+ }
+ };
+
+
+ static mframe_t supertank_frames_turn_right[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, TreadSound),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_turn_right = new mmove_t(FRAME_right_1, FRAME_right_18, supertank_frames_turn_right, supertank_run);
+
+ static mframe_t supertank_frames_turn_left[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, TreadSound),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_turn_left = new mmove_t(FRAME_left_1, FRAME_left_18, supertank_frames_turn_left, supertank_run);
+
+ static mframe_t supertank_frames_pain3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_pain3 = new mmove_t(FRAME_pain3_9, FRAME_pain3_12, supertank_frames_pain3, supertank_run);
+
+ static mframe_t supertank_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_pain2 = new mmove_t(FRAME_pain2_5, FRAME_pain2_8, supertank_frames_pain2, supertank_run);
+
+ static mframe_t supertank_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_pain1 = new mmove_t(FRAME_pain1_1, FRAME_pain1_4, supertank_frames_pain1, supertank_run);
+
+ static mframe_t supertank_frames_death1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, BossExplode)};
+ static mmove_t supertank_move_death = new mmove_t(FRAME_death_1, FRAME_death_24, supertank_frames_death1, supertank_dead);
+
+ static mframe_t supertank_frames_backward[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 0, TreadSound),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 0, null)};
+ static mmove_t supertank_move_backward = new mmove_t(FRAME_backwd_1, FRAME_backwd_18, supertank_frames_backward, null);
+
+ static mframe_t supertank_frames_attack4[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_attack4 = new mmove_t(FRAME_attak4_1, FRAME_attak4_6, supertank_frames_attack4, supertank_run);
+
+ static mframe_t supertank_frames_attack3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_attack3 = new mmove_t(FRAME_attak3_1, FRAME_attak3_27, supertank_frames_attack3, supertank_run);
+
+ static mframe_t supertank_frames_attack2[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, supertankRocket),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, supertankRocket),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, supertankRocket),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_attack2 = new mmove_t(FRAME_attak2_1, FRAME_attak2_27, supertank_frames_attack2, supertank_run);
+
+ static EntThinkAdapter supertank_reattack1 = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (visible(self, self.enemy))
+ if (Lib.random() < 0.9)
+ self.monsterinfo.currentmove = supertank_move_attack1;
+ else
+ self.monsterinfo.currentmove = supertank_move_end_attack1;
+ else
+ self.monsterinfo.currentmove = supertank_move_end_attack1;
+ return true;
+ }
+ };
+
+
+
+ static mframe_t supertank_frames_attack1[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, supertankMachineGun),
+ new mframe_t(ai_charge, 0, supertankMachineGun),
+ new mframe_t(ai_charge, 0, supertankMachineGun),
+ new mframe_t(ai_charge, 0, supertankMachineGun),
+ new mframe_t(ai_charge, 0, supertankMachineGun),
+ new mframe_t(ai_charge, 0, supertankMachineGun),
+ };
+ static mmove_t supertank_move_attack1 = new mmove_t(FRAME_attak1_1, FRAME_attak1_6, supertank_frames_attack1, supertank_reattack1);
+
+ static mframe_t supertank_frames_end_attack1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t supertank_move_end_attack1 =
+ new mmove_t(FRAME_attak1_7, FRAME_attak1_20, supertank_frames_end_attack1, supertank_run);
+
+ static EntPainAdapter supertank_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum = 1;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ // Lessen the chance of him going into his pain frames
+ if (damage <= 25)
+ if (Lib.random() < 0.2)
+ return;
+
+ // Don't go into pain if he's firing his rockets
+ if (skill.value >= 2)
+ if ((self.s.frame >= FRAME_attak2_1) && (self.s.frame <= FRAME_attak2_14))
+ return;
+
+ self.pain_debounce_time = level.time + 3;
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (damage <= 10) {
+ gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = supertank_move_pain1;
+ } else if (damage <= 25) {
+ gi.sound(self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = supertank_move_pain2;
+ } else {
+ gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
+ self.monsterinfo.currentmove = supertank_move_pain3;
+ }
+ }
+ };
+
+
+
+ void BossExplode(edict_t self) {
+ float[] org={0,0,0};
+ int n;
+
+ self.think = BossExplode;
+ Math3D.VectorCopy(self.s.origin, org);
+ org[2] += 24 + (Lib.rand() & 15);
+ switch (self.count++) {
+ case 0 :
+ org[0] -= 24;
+ org[1] -= 24;
+ break;
+ case 1 :
+ org[0] += 24;
+ org[1] += 24;
+ break;
+ case 2 :
+ org[0] += 24;
+ org[1] -= 24;
+ break;
+ case 3 :
+ org[0] -= 24;
+ org[1] += 24;
+ break;
+ case 4 :
+ org[0] -= 48;
+ org[1] -= 48;
+ break;
+ case 5 :
+ org[0] += 48;
+ org[1] += 48;
+ break;
+ case 6 :
+ org[0] -= 48;
+ org[1] += 48;
+ break;
+ case 7 :
+ org[0] += 48;
+ org[1] -= 48;
+ break;
+ case 8 :
+ self.s.sound = 0;
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", 500, GIB_ORGANIC);
+ for (n = 0; n < 8; n++)
+ ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", 500, GIB_METALLIC);
+ ThrowGib(self, "models/objects/gibs/chest/tris.md2", 500, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/gear/tris.md2", 500, GIB_METALLIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ gi.WriteByte(svc_temp_entity);
+ gi.WriteByte(TE_EXPLOSION1);
+ gi.WritePosition(org);
+ gi.multicast(self.s.origin, MULTICAST_PVS);
+
+ self.nextthink = level.time + 0.1f;
+ }
+
+ static EntDieAdapter supertank_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_NO;
+ self.count = 0;
+ self.monsterinfo.currentmove = supertank_move_death;
+ }
+ };
+
+ //
+ // monster_supertank
+ //
+
+ /*QUAKED monster_supertank (1 .5 0) (-64 -64 0) (64 64 72) Ambush Trigger_Spawn Sight
+ */
+ static EntThinkAdapter SP_monster_supertank = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return true;
+ }
+
+ sound_pain1 = gi.soundindex("bosstank/btkpain1.wav");
+ sound_pain2 = gi.soundindex("bosstank/btkpain2.wav");
+ sound_pain3 = gi.soundindex("bosstank/btkpain3.wav");
+ sound_death = gi.soundindex("bosstank/btkdeth1.wav");
+ sound_search1 = gi.soundindex("bosstank/btkunqv1.wav");
+ sound_search2 = gi.soundindex("bosstank/btkunqv2.wav");
+
+ // self.s.sound = gi.soundindex ("bosstank/btkengn1.wav");
+ tread_sound = gi.soundindex("bosstank/btkengn1.wav");
+
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+ self.s.modelindex = gi.modelindex("models/monsters/boss1/tris.md2");
+ Math3D.VectorSet(self.mins, -64, -64, 0);
+ Math3D.VectorSet(self.maxs, 64, 64, 112);
+
+ self.health = 1500;
+ self.gib_health = -500;
+ self.mass = 800;
+
+ self.pain = supertank_pain;
+ self.die = supertank_die;
+ self.monsterinfo.stand = supertank_stand;
+ self.monsterinfo.walk = supertank_walk;
+ self.monsterinfo.run = supertank_run;
+ self.monsterinfo.dodge = null;
+ self.monsterinfo.attack = supertank_attack;
+ self.monsterinfo.search = supertank_search;
+ self.monsterinfo.melee = null;
+ self.monsterinfo.sight = null;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = supertank_move_stand;
+ self.monsterinfo.scale = MODEL_SCALE;
+
+ walkmonster_start.think(self);
+ return true;
+ }
+ };
+
+
+}
diff --git a/src/jake2/game/M_Tank.java b/src/jake2/game/M_Tank.java
new file mode 100644
index 0000000..a91b760
--- /dev/null
+++ b/src/jake2/game/M_Tank.java
@@ -0,0 +1,1143 @@
+/*
+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 13.11.2003 by RST.
+// $Id: M_Tank.java,v 1.1 2004-07-07 19:59:20 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class M_Tank extends GamePWeapon {
+ // G:\quake2\baseq2\models/monsters/tank
+
+ // This file generated by qdata - Do NOT Modify
+
+ public final static int FRAME_stand01 = 0;
+ public final static int FRAME_stand02 = 1;
+ public final static int FRAME_stand03 = 2;
+ public final static int FRAME_stand04 = 3;
+ public final static int FRAME_stand05 = 4;
+ public final static int FRAME_stand06 = 5;
+ public final static int FRAME_stand07 = 6;
+ public final static int FRAME_stand08 = 7;
+ public final static int FRAME_stand09 = 8;
+ public final static int FRAME_stand10 = 9;
+ public final static int FRAME_stand11 = 10;
+ public final static int FRAME_stand12 = 11;
+ public final static int FRAME_stand13 = 12;
+ public final static int FRAME_stand14 = 13;
+ public final static int FRAME_stand15 = 14;
+ public final static int FRAME_stand16 = 15;
+ public final static int FRAME_stand17 = 16;
+ public final static int FRAME_stand18 = 17;
+ public final static int FRAME_stand19 = 18;
+ public final static int FRAME_stand20 = 19;
+ public final static int FRAME_stand21 = 20;
+ public final static int FRAME_stand22 = 21;
+ public final static int FRAME_stand23 = 22;
+ public final static int FRAME_stand24 = 23;
+ public final static int FRAME_stand25 = 24;
+ public final static int FRAME_stand26 = 25;
+ public final static int FRAME_stand27 = 26;
+ public final static int FRAME_stand28 = 27;
+ public final static int FRAME_stand29 = 28;
+ public final static int FRAME_stand30 = 29;
+ public final static int FRAME_walk01 = 30;
+ public final static int FRAME_walk02 = 31;
+ public final static int FRAME_walk03 = 32;
+ public final static int FRAME_walk04 = 33;
+ public final static int FRAME_walk05 = 34;
+ public final static int FRAME_walk06 = 35;
+ public final static int FRAME_walk07 = 36;
+ public final static int FRAME_walk08 = 37;
+ public final static int FRAME_walk09 = 38;
+ public final static int FRAME_walk10 = 39;
+ public final static int FRAME_walk11 = 40;
+ public final static int FRAME_walk12 = 41;
+ public final static int FRAME_walk13 = 42;
+ public final static int FRAME_walk14 = 43;
+ public final static int FRAME_walk15 = 44;
+ public final static int FRAME_walk16 = 45;
+ public final static int FRAME_walk17 = 46;
+ public final static int FRAME_walk18 = 47;
+ public final static int FRAME_walk19 = 48;
+ public final static int FRAME_walk20 = 49;
+ public final static int FRAME_walk21 = 50;
+ public final static int FRAME_walk22 = 51;
+ public final static int FRAME_walk23 = 52;
+ public final static int FRAME_walk24 = 53;
+ public final static int FRAME_walk25 = 54;
+ public final static int FRAME_attak101 = 55;
+ public final static int FRAME_attak102 = 56;
+ public final static int FRAME_attak103 = 57;
+ public final static int FRAME_attak104 = 58;
+ public final static int FRAME_attak105 = 59;
+ public final static int FRAME_attak106 = 60;
+ public final static int FRAME_attak107 = 61;
+ public final static int FRAME_attak108 = 62;
+ public final static int FRAME_attak109 = 63;
+ public final static int FRAME_attak110 = 64;
+ public final static int FRAME_attak111 = 65;
+ public final static int FRAME_attak112 = 66;
+ public final static int FRAME_attak113 = 67;
+ public final static int FRAME_attak114 = 68;
+ public final static int FRAME_attak115 = 69;
+ public final static int FRAME_attak116 = 70;
+ public final static int FRAME_attak117 = 71;
+ public final static int FRAME_attak118 = 72;
+ public final static int FRAME_attak119 = 73;
+ public final static int FRAME_attak120 = 74;
+ public final static int FRAME_attak121 = 75;
+ public final static int FRAME_attak122 = 76;
+ public final static int FRAME_attak201 = 77;
+ public final static int FRAME_attak202 = 78;
+ public final static int FRAME_attak203 = 79;
+ public final static int FRAME_attak204 = 80;
+ public final static int FRAME_attak205 = 81;
+ public final static int FRAME_attak206 = 82;
+ public final static int FRAME_attak207 = 83;
+ public final static int FRAME_attak208 = 84;
+ public final static int FRAME_attak209 = 85;
+ public final static int FRAME_attak210 = 86;
+ public final static int FRAME_attak211 = 87;
+ public final static int FRAME_attak212 = 88;
+ public final static int FRAME_attak213 = 89;
+ public final static int FRAME_attak214 = 90;
+ public final static int FRAME_attak215 = 91;
+ public final static int FRAME_attak216 = 92;
+ public final static int FRAME_attak217 = 93;
+ public final static int FRAME_attak218 = 94;
+ public final static int FRAME_attak219 = 95;
+ public final static int FRAME_attak220 = 96;
+ public final static int FRAME_attak221 = 97;
+ public final static int FRAME_attak222 = 98;
+ public final static int FRAME_attak223 = 99;
+ public final static int FRAME_attak224 = 100;
+ public final static int FRAME_attak225 = 101;
+ public final static int FRAME_attak226 = 102;
+ public final static int FRAME_attak227 = 103;
+ public final static int FRAME_attak228 = 104;
+ public final static int FRAME_attak229 = 105;
+ public final static int FRAME_attak230 = 106;
+ public final static int FRAME_attak231 = 107;
+ public final static int FRAME_attak232 = 108;
+ public final static int FRAME_attak233 = 109;
+ public final static int FRAME_attak234 = 110;
+ public final static int FRAME_attak235 = 111;
+ public final static int FRAME_attak236 = 112;
+ public final static int FRAME_attak237 = 113;
+ public final static int FRAME_attak238 = 114;
+ public final static int FRAME_attak301 = 115;
+ public final static int FRAME_attak302 = 116;
+ public final static int FRAME_attak303 = 117;
+ public final static int FRAME_attak304 = 118;
+ public final static int FRAME_attak305 = 119;
+ public final static int FRAME_attak306 = 120;
+ public final static int FRAME_attak307 = 121;
+ public final static int FRAME_attak308 = 122;
+ public final static int FRAME_attak309 = 123;
+ public final static int FRAME_attak310 = 124;
+ public final static int FRAME_attak311 = 125;
+ public final static int FRAME_attak312 = 126;
+ public final static int FRAME_attak313 = 127;
+ public final static int FRAME_attak314 = 128;
+ public final static int FRAME_attak315 = 129;
+ public final static int FRAME_attak316 = 130;
+ public final static int FRAME_attak317 = 131;
+ public final static int FRAME_attak318 = 132;
+ public final static int FRAME_attak319 = 133;
+ public final static int FRAME_attak320 = 134;
+ public final static int FRAME_attak321 = 135;
+ public final static int FRAME_attak322 = 136;
+ public final static int FRAME_attak323 = 137;
+ public final static int FRAME_attak324 = 138;
+ public final static int FRAME_attak325 = 139;
+ public final static int FRAME_attak326 = 140;
+ public final static int FRAME_attak327 = 141;
+ public final static int FRAME_attak328 = 142;
+ public final static int FRAME_attak329 = 143;
+ public final static int FRAME_attak330 = 144;
+ public final static int FRAME_attak331 = 145;
+ public final static int FRAME_attak332 = 146;
+ public final static int FRAME_attak333 = 147;
+ public final static int FRAME_attak334 = 148;
+ public final static int FRAME_attak335 = 149;
+ public final static int FRAME_attak336 = 150;
+ public final static int FRAME_attak337 = 151;
+ public final static int FRAME_attak338 = 152;
+ public final static int FRAME_attak339 = 153;
+ public final static int FRAME_attak340 = 154;
+ public final static int FRAME_attak341 = 155;
+ public final static int FRAME_attak342 = 156;
+ public final static int FRAME_attak343 = 157;
+ public final static int FRAME_attak344 = 158;
+ public final static int FRAME_attak345 = 159;
+ public final static int FRAME_attak346 = 160;
+ public final static int FRAME_attak347 = 161;
+ public final static int FRAME_attak348 = 162;
+ public final static int FRAME_attak349 = 163;
+ public final static int FRAME_attak350 = 164;
+ public final static int FRAME_attak351 = 165;
+ public final static int FRAME_attak352 = 166;
+ public final static int FRAME_attak353 = 167;
+ public final static int FRAME_attak401 = 168;
+ public final static int FRAME_attak402 = 169;
+ public final static int FRAME_attak403 = 170;
+ public final static int FRAME_attak404 = 171;
+ public final static int FRAME_attak405 = 172;
+ public final static int FRAME_attak406 = 173;
+ public final static int FRAME_attak407 = 174;
+ public final static int FRAME_attak408 = 175;
+ public final static int FRAME_attak409 = 176;
+ public final static int FRAME_attak410 = 177;
+ public final static int FRAME_attak411 = 178;
+ public final static int FRAME_attak412 = 179;
+ public final static int FRAME_attak413 = 180;
+ public final static int FRAME_attak414 = 181;
+ public final static int FRAME_attak415 = 182;
+ public final static int FRAME_attak416 = 183;
+ public final static int FRAME_attak417 = 184;
+ public final static int FRAME_attak418 = 185;
+ public final static int FRAME_attak419 = 186;
+ public final static int FRAME_attak420 = 187;
+ public final static int FRAME_attak421 = 188;
+ public final static int FRAME_attak422 = 189;
+ public final static int FRAME_attak423 = 190;
+ public final static int FRAME_attak424 = 191;
+ public final static int FRAME_attak425 = 192;
+ public final static int FRAME_attak426 = 193;
+ public final static int FRAME_attak427 = 194;
+ public final static int FRAME_attak428 = 195;
+ public final static int FRAME_attak429 = 196;
+ public final static int FRAME_pain101 = 197;
+ public final static int FRAME_pain102 = 198;
+ public final static int FRAME_pain103 = 199;
+ public final static int FRAME_pain104 = 200;
+ public final static int FRAME_pain201 = 201;
+ public final static int FRAME_pain202 = 202;
+ public final static int FRAME_pain203 = 203;
+ public final static int FRAME_pain204 = 204;
+ public final static int FRAME_pain205 = 205;
+ public final static int FRAME_pain301 = 206;
+ public final static int FRAME_pain302 = 207;
+ public final static int FRAME_pain303 = 208;
+ public final static int FRAME_pain304 = 209;
+ public final static int FRAME_pain305 = 210;
+ public final static int FRAME_pain306 = 211;
+ public final static int FRAME_pain307 = 212;
+ public final static int FRAME_pain308 = 213;
+ public final static int FRAME_pain309 = 214;
+ public final static int FRAME_pain310 = 215;
+ public final static int FRAME_pain311 = 216;
+ public final static int FRAME_pain312 = 217;
+ public final static int FRAME_pain313 = 218;
+ public final static int FRAME_pain314 = 219;
+ public final static int FRAME_pain315 = 220;
+ public final static int FRAME_pain316 = 221;
+ public final static int FRAME_death101 = 222;
+ public final static int FRAME_death102 = 223;
+ public final static int FRAME_death103 = 224;
+ public final static int FRAME_death104 = 225;
+ public final static int FRAME_death105 = 226;
+ public final static int FRAME_death106 = 227;
+ public final static int FRAME_death107 = 228;
+ public final static int FRAME_death108 = 229;
+ public final static int FRAME_death109 = 230;
+ public final static int FRAME_death110 = 231;
+ public final static int FRAME_death111 = 232;
+ public final static int FRAME_death112 = 233;
+ public final static int FRAME_death113 = 234;
+ public final static int FRAME_death114 = 235;
+ public final static int FRAME_death115 = 236;
+ public final static int FRAME_death116 = 237;
+ public final static int FRAME_death117 = 238;
+ public final static int FRAME_death118 = 239;
+ public final static int FRAME_death119 = 240;
+ public final static int FRAME_death120 = 241;
+ public final static int FRAME_death121 = 242;
+ public final static int FRAME_death122 = 243;
+ public final static int FRAME_death123 = 244;
+ public final static int FRAME_death124 = 245;
+ public final static int FRAME_death125 = 246;
+ public final static int FRAME_death126 = 247;
+ public final static int FRAME_death127 = 248;
+ public final static int FRAME_death128 = 249;
+ public final static int FRAME_death129 = 250;
+ public final static int FRAME_death130 = 251;
+ public final static int FRAME_death131 = 252;
+ public final static int FRAME_death132 = 253;
+ public final static int FRAME_recln101 = 254;
+ public final static int FRAME_recln102 = 255;
+ public final static int FRAME_recln103 = 256;
+ public final static int FRAME_recln104 = 257;
+ public final static int FRAME_recln105 = 258;
+ public final static int FRAME_recln106 = 259;
+ public final static int FRAME_recln107 = 260;
+ public final static int FRAME_recln108 = 261;
+ public final static int FRAME_recln109 = 262;
+ public final static int FRAME_recln110 = 263;
+ public final static int FRAME_recln111 = 264;
+ public final static int FRAME_recln112 = 265;
+ public final static int FRAME_recln113 = 266;
+ public final static int FRAME_recln114 = 267;
+ public final static int FRAME_recln115 = 268;
+ public final static int FRAME_recln116 = 269;
+ public final static int FRAME_recln117 = 270;
+ public final static int FRAME_recln118 = 271;
+ public final static int FRAME_recln119 = 272;
+ public final static int FRAME_recln120 = 273;
+ public final static int FRAME_recln121 = 274;
+ public final static int FRAME_recln122 = 275;
+ public final static int FRAME_recln123 = 276;
+ public final static int FRAME_recln124 = 277;
+ public final static int FRAME_recln125 = 278;
+ public final static int FRAME_recln126 = 279;
+ public final static int FRAME_recln127 = 280;
+ public final static int FRAME_recln128 = 281;
+ public final static int FRAME_recln129 = 282;
+ public final static int FRAME_recln130 = 283;
+ public final static int FRAME_recln131 = 284;
+ public final static int FRAME_recln132 = 285;
+ public final static int FRAME_recln133 = 286;
+ public final static int FRAME_recln134 = 287;
+ public final static int FRAME_recln135 = 288;
+ public final static int FRAME_recln136 = 289;
+ public final static int FRAME_recln137 = 290;
+ public final static int FRAME_recln138 = 291;
+ public final static int FRAME_recln139 = 292;
+ public final static int FRAME_recln140 = 293;
+
+ public final static float MODEL_SCALE = 1.000000f;
+
+ static int sound_thud;
+ static int sound_pain;
+ static int sound_idle;
+ static int sound_die;
+ static int sound_step;
+ static int sound_sight;
+ static int sound_windup;
+ static int sound_strike;
+
+ //
+ // misc
+ //
+
+ static EntInteractAdapter tank_sight = new EntInteractAdapter() {
+ public boolean think(edict_t self, edict_t other) {
+ gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter tank_footstep = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter tank_thud = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter tank_windup = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter tank_idle = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
+ return true;
+ }
+ };
+
+ //
+ // stand
+ //
+
+ static mframe_t tank_frames_stand[] =
+ new mframe_t[] {
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null),
+ new mframe_t(ai_stand, 0, null)};
+ static mmove_t tank_move_stand = new mmove_t(FRAME_stand01, FRAME_stand30, tank_frames_stand, null);
+
+ static EntThinkAdapter tank_stand = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = tank_move_stand;
+ return true;
+ }
+ };
+
+ //
+ // walk
+ //
+ static EntThinkAdapter tank_run = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.enemy != null && self.enemy.client != null)
+ self.monsterinfo.aiflags |= AI_BRUTAL;
+ else
+ self.monsterinfo.aiflags &= ~AI_BRUTAL;
+
+ if ((self.monsterinfo.aiflags & AI_STAND_GROUND) != 0) {
+ self.monsterinfo.currentmove = tank_move_stand;
+ return true;
+ }
+
+ if (self.monsterinfo.currentmove == tank_move_walk || self.monsterinfo.currentmove == tank_move_start_run) {
+ self.monsterinfo.currentmove = tank_move_run;
+ } else {
+ self.monsterinfo.currentmove = tank_move_start_run;
+ }
+ return true;
+ }
+ };
+
+ static EntThinkAdapter tank_walk = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = tank_move_walk;
+ return true;
+ }
+ };
+
+ static mframe_t tank_frames_start_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 0, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 11, tank_footstep)};
+ static mmove_t tank_move_start_walk = new mmove_t(FRAME_walk01, FRAME_walk04, tank_frames_start_walk, tank_walk);
+
+ static mframe_t tank_frames_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 4, tank_footstep),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 4, null),
+ new mframe_t(ai_walk, 5, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 7, null),
+ new mframe_t(ai_walk, 6, null),
+ new mframe_t(ai_walk, 6, tank_footstep)};
+ static mmove_t tank_move_walk = new mmove_t(FRAME_walk05, FRAME_walk20, tank_frames_walk, null);
+
+ static mframe_t tank_frames_stop_walk[] =
+ new mframe_t[] {
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 3, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 2, null),
+ new mframe_t(ai_walk, 4, tank_footstep)};
+ static mmove_t tank_move_stop_walk = new mmove_t(FRAME_walk21, FRAME_walk25, tank_frames_stop_walk, tank_stand);
+
+ //
+ // run
+ //
+
+ static mframe_t tank_frames_start_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 0, null),
+ new mframe_t(ai_run, 6, null),
+ new mframe_t(ai_run, 6, null),
+ new mframe_t(ai_run, 11, tank_footstep)};
+ static mmove_t tank_move_start_run = new mmove_t(FRAME_walk01, FRAME_walk04, tank_frames_start_run, tank_run);
+
+ static mframe_t tank_frames_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 4, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 3, null),
+ new mframe_t(ai_run, 2, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 4, null),
+ new mframe_t(ai_run, 4, tank_footstep),
+ new mframe_t(ai_run, 3, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 4, null),
+ new mframe_t(ai_run, 5, null),
+ new mframe_t(ai_run, 7, null),
+ new mframe_t(ai_run, 7, null),
+ new mframe_t(ai_run, 6, null),
+ new mframe_t(ai_run, 6, tank_footstep)};
+ static mmove_t tank_move_run = new mmove_t(FRAME_walk05, FRAME_walk20, tank_frames_run, null);
+
+ static mframe_t tank_frames_stop_run[] =
+ new mframe_t[] {
+ new mframe_t(ai_run, 3, null),
+ new mframe_t(ai_run, 3, null),
+ new mframe_t(ai_run, 2, null),
+ new mframe_t(ai_run, 2, null),
+ new mframe_t(ai_run, 4, tank_footstep)};
+ static mmove_t tank_move_stop_run = new mmove_t(FRAME_walk21, FRAME_walk25, tank_frames_stop_run, tank_walk);
+
+ //
+ // pain
+ //
+
+ static mframe_t tank_frames_pain1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t tank_move_pain1 = new mmove_t(FRAME_pain101, FRAME_pain104, tank_frames_pain1, tank_run);
+
+ static mframe_t tank_frames_pain2[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t tank_move_pain2 = new mmove_t(FRAME_pain201, FRAME_pain205, tank_frames_pain2, tank_run);
+
+ static mframe_t tank_frames_pain3[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, tank_footstep)};
+ static mmove_t tank_move_pain3 = new mmove_t(FRAME_pain301, FRAME_pain316, tank_frames_pain3, tank_run);
+
+ static EntPainAdapter tank_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ if (self.health < (self.max_health / 2))
+ self.s.skinnum |= 1;
+
+ if (damage <= 10)
+ return;
+
+ if (level.time < self.pain_debounce_time)
+ return;
+
+ if (damage <= 30)
+ if (Lib.random() > 0.2)
+ return;
+
+ // If hard or nightmare, don't go into pain while attacking
+ if (skill.value >= 2) {
+ if ((self.s.frame >= FRAME_attak301) && (self.s.frame <= FRAME_attak330))
+ return;
+ if ((self.s.frame >= FRAME_attak101) && (self.s.frame <= FRAME_attak116))
+ return;
+ }
+
+ self.pain_debounce_time = level.time + 3;
+ gi.sound(self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
+
+ if (skill.value == 3)
+ return; // no pain anims in nightmare
+
+ if (damage <= 30)
+ self.monsterinfo.currentmove = tank_move_pain1;
+ else if (damage <= 60)
+ self.monsterinfo.currentmove = tank_move_pain2;
+ else
+ self.monsterinfo.currentmove = tank_move_pain3;
+ }
+ };
+
+ //
+ // attacks
+ //
+
+ static EntThinkAdapter TankBlaster = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 };
+ float[] start = { 0, 0, 0 };
+ float[] end = { 0, 0, 0 };
+ float[] dir = { 0, 0, 0 };
+ int flash_number;
+
+ if (self.s.frame == FRAME_attak110)
+ flash_number = MZ2_TANK_BLASTER_1;
+ else if (self.s.frame == FRAME_attak113)
+ flash_number = MZ2_TANK_BLASTER_2;
+ else // (self.s.frame == FRAME_attak116)
+ flash_number = MZ2_TANK_BLASTER_3;
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, end);
+ end[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(end, start, dir);
+
+ Monster.monster_fire_blaster(self, start, dir, 30, 800, flash_number, EF_BLASTER);
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter TankStrike = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ gi.sound(self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0);
+
+ return true;
+ }
+ };
+
+ static EntThinkAdapter TankRocket = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 };
+ float[] start = { 0, 0, 0 };
+ float[] dir = { 0, 0, 0 };
+ float[] vec = { 0, 0, 0 };
+ int flash_number;
+
+ if (self.s.frame == FRAME_attak324)
+ flash_number = MZ2_TANK_ROCKET_1;
+ else if (self.s.frame == FRAME_attak327)
+ flash_number = MZ2_TANK_ROCKET_2;
+ else // (self.s.frame == FRAME_attak330)
+ flash_number = MZ2_TANK_ROCKET_3;
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, dir);
+ Math3D.VectorNormalize(dir);
+
+ Monster.monster_fire_rocket(self, start, dir, 50, 550, flash_number);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter TankMachineGun = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ float[] dir = { 0, 0, 0 };
+ float[] vec = { 0, 0, 0 };
+ float[] start = { 0, 0, 0 };
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 };
+ int flash_number;
+
+ flash_number = MZ2_TANK_MACHINEGUN_1 + (self.s.frame - FRAME_attak406);
+
+ Math3D.AngleVectors(self.s.angles, forward, right, null);
+ Math3D.G_ProjectSource(self.s.origin, monster_flash_offset[flash_number], forward, right, start);
+
+ if (self.enemy != null) {
+ Math3D.VectorCopy(self.enemy.s.origin, vec);
+ vec[2] += self.enemy.viewheight;
+ Math3D.VectorSubtract(vec, start, vec);
+ Math3D.vectoangles(vec, vec);
+ dir[0] = vec[0];
+ } else {
+ dir[0] = 0;
+ }
+ if (self.s.frame <= FRAME_attak415)
+ dir[1] = self.s.angles[1] - 8 * (self.s.frame - FRAME_attak411);
+ else
+ dir[1] = self.s.angles[1] + 8 * (self.s.frame - FRAME_attak419);
+ dir[2] = 0;
+
+ Math3D.AngleVectors(dir, forward, null, null);
+
+ Monster.monster_fire_bullet(self, start, forward, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
+
+ return true;
+ }
+ };
+ static EntThinkAdapter tank_reattack_blaster = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (skill.value >= 2)
+ if (visible(self, self.enemy))
+ if (self.enemy.health > 0)
+ if (Lib.random() <= 0.6) {
+ self.monsterinfo.currentmove = tank_move_reattack_blast;
+ return true;
+ }
+ self.monsterinfo.currentmove = tank_move_attack_post_blast;
+ return true;
+ }
+ };
+
+ static mframe_t tank_frames_attack_blast[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -2, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, TankBlaster),
+ // 10
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, TankBlaster),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, TankBlaster) // 16
+ };
+ static mmove_t tank_move_attack_blast =
+ new mmove_t(FRAME_attak101, FRAME_attak116, tank_frames_attack_blast, tank_reattack_blaster);
+
+ static mframe_t tank_frames_reattack_blast[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, TankBlaster),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, TankBlaster) // 16)
+ };
+ static mmove_t tank_move_reattack_blast =
+ new mmove_t(FRAME_attak111, FRAME_attak116, tank_frames_reattack_blast, tank_reattack_blaster);
+
+ static mframe_t tank_frames_attack_post_blast[] = new mframe_t[] { new mframe_t(ai_move, 0, null), // 17)
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, -2, tank_footstep) // 22
+ };
+ static mmove_t tank_move_attack_post_blast = new mmove_t(FRAME_attak117, FRAME_attak122, tank_frames_attack_post_blast, tank_run);
+
+ static EntThinkAdapter tank_poststrike = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.enemy = null;
+ tank_run.think(self);
+ return true;
+ }
+ };
+
+ static EntThinkAdapter tank_doattack_rocket = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.monsterinfo.currentmove = tank_move_attack_fire_rocket;
+ return true;
+ }
+ };
+
+ static EntThinkAdapter tank_refire_rocket = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ // Only on hard or nightmare
+ if (skill.value >= 2)
+ if (self.enemy.health > 0)
+ if (visible(self, self.enemy))
+ if (Lib.random() <= 0.4) {
+ self.monsterinfo.currentmove = tank_move_attack_fire_rocket;
+ return true;
+ }
+ self.monsterinfo.currentmove = tank_move_attack_post_rocket;
+ return true;
+ }
+ };
+
+ static mframe_t tank_frames_attack_strike[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 7, null),
+ new mframe_t(ai_move, 9, tank_footstep),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 2, tank_footstep),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 0, tank_windup),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, TankStrike),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -1, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -10, null),
+ new mframe_t(ai_move, -10, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, -2, tank_footstep)};
+ static mmove_t tank_move_attack_strike = new mmove_t(FRAME_attak201, FRAME_attak238, tank_frames_attack_strike, tank_poststrike);
+
+ static mframe_t tank_frames_attack_pre_rocket[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ // 10)
+
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 1, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, 7, null),
+ new mframe_t(ai_charge, 7, null),
+ new mframe_t(ai_charge, 7, tank_footstep),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ // 20)
+
+ new mframe_t(ai_charge, -3, null)};
+ static mmove_t tank_move_attack_pre_rocket =
+ new mmove_t(FRAME_attak301, FRAME_attak321, tank_frames_attack_pre_rocket, tank_doattack_rocket);
+
+ static mframe_t tank_frames_attack_fire_rocket[] = new mframe_t[] { new mframe_t(ai_charge, -3, null), // Loop Start 22 )
+ new mframe_t(ai_charge, 0, null), new mframe_t(ai_charge, 0, TankRocket), // 24)
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, TankRocket),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -1, TankRocket) // 30 Loop End
+ };
+ static mmove_t tank_move_attack_fire_rocket =
+ new mmove_t(FRAME_attak322, FRAME_attak330, tank_frames_attack_fire_rocket, tank_refire_rocket);
+
+ static mframe_t tank_frames_attack_post_rocket[] = new mframe_t[] { new mframe_t(ai_charge, 0, null), // 31)
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, 3, null),
+ new mframe_t(ai_charge, 4, null),
+ new mframe_t(ai_charge, 2, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ // 40)
+
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, -9, null),
+ new mframe_t(ai_charge, -8, null),
+ new mframe_t(ai_charge, -7, null),
+ new mframe_t(ai_charge, -1, null),
+ new mframe_t(ai_charge, -1, tank_footstep),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ // 50)
+
+ new mframe_t(ai_charge, 0, null), new mframe_t(ai_charge, 0, null), new mframe_t(ai_charge, 0, null)};
+ static mmove_t tank_move_attack_post_rocket =
+ new mmove_t(FRAME_attak331, FRAME_attak353, tank_frames_attack_post_rocket, tank_run);
+
+ static mframe_t tank_frames_attack_chain[] =
+ new mframe_t[] {
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(null, 0, TankMachineGun),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null),
+ new mframe_t(ai_charge, 0, null)};
+
+ static mmove_t tank_move_attack_chain = new mmove_t(FRAME_attak401, FRAME_attak429, tank_frames_attack_chain, tank_run);
+
+ static EntThinkAdapter tank_attack = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ float[] vec = { 0, 0, 0 };
+ float range;
+ float r;
+
+ if (self.enemy.health < 0) {
+ self.monsterinfo.currentmove = tank_move_attack_strike;
+ self.monsterinfo.aiflags &= ~AI_BRUTAL;
+ return true;
+ }
+
+ Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, vec);
+ range = Math3D.VectorLength(vec);
+
+ r = Lib.random();
+
+ if (range <= 125) {
+ if (r < 0.4)
+ self.monsterinfo.currentmove = tank_move_attack_chain;
+ else
+ self.monsterinfo.currentmove = tank_move_attack_blast;
+ } else if (range <= 250) {
+ if (r < 0.5)
+ self.monsterinfo.currentmove = tank_move_attack_chain;
+ else
+ self.monsterinfo.currentmove = tank_move_attack_blast;
+ } else {
+ if (r < 0.33)
+ self.monsterinfo.currentmove = tank_move_attack_chain;
+ else if (r < 0.66) {
+ self.monsterinfo.currentmove = tank_move_attack_pre_rocket;
+ self.pain_debounce_time = level.time + 5.0f; // no pain for a while
+ } else
+ self.monsterinfo.currentmove = tank_move_attack_blast;
+ }
+ return true;
+ }
+ };
+
+ //
+ // death
+ //
+ static EntThinkAdapter tank_dead = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ Math3D.VectorSet(self.mins, -16, -16, -16);
+ Math3D.VectorSet(self.maxs, 16, 16, -0);
+ self.movetype = MOVETYPE_TOSS;
+ self.svflags |= SVF_DEADMONSTER;
+ self.nextthink = 0;
+ gi.linkentity(self);
+ return true;
+ }
+ };
+
+ static mframe_t tank_frames_death1[] =
+ new mframe_t[] {
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 3, null),
+ new mframe_t(ai_move, 6, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 1, null),
+ new mframe_t(ai_move, 2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -2, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -3, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -6, null),
+ new mframe_t(ai_move, -4, null),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, -7, null),
+ new mframe_t(ai_move, -15, tank_thud),
+ new mframe_t(ai_move, -5, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null),
+ new mframe_t(ai_move, 0, null)};
+ static mmove_t tank_move_death = new mmove_t(FRAME_death101, FRAME_death132, tank_frames_death1, tank_dead);
+
+ static EntDieAdapter tank_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+ int n;
+
+ // check for gib
+ if (self.health <= self.gib_health) {
+ gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 1 /*4*/; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
+ ThrowGib(self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
+ ThrowHead(self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
+ self.deadflag = DEAD_DEAD;
+ return;
+ }
+
+ if (self.deadflag == DEAD_DEAD)
+ return;
+
+ // regular death
+ gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
+ self.deadflag = DEAD_DEAD;
+ self.takedamage = DAMAGE_YES;
+
+ self.monsterinfo.currentmove = tank_move_death;
+
+ }
+ };
+
+ //
+ // monster_tank
+ //
+
+ /*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
+ */
+ /*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
+ */
+ static EntThinkAdapter SP_monster_tank = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (deathmatch.value != 0) {
+ G_FreeEdict(self);
+ return true;
+ }
+
+ self.s.modelindex = gi.modelindex("models/monsters/tank/tris.md2");
+ Math3D.VectorSet(self.mins, -32, -32, -16);
+ Math3D.VectorSet(self.maxs, 32, 32, 72);
+ self.movetype = MOVETYPE_STEP;
+ self.solid = SOLID_BBOX;
+
+ sound_pain = gi.soundindex("tank/tnkpain2.wav");
+ sound_thud = gi.soundindex("tank/tnkdeth2.wav");
+ sound_idle = gi.soundindex("tank/tnkidle1.wav");
+ sound_die = gi.soundindex("tank/death.wav");
+ sound_step = gi.soundindex("tank/step.wav");
+ sound_windup = gi.soundindex("tank/tnkatck4.wav");
+ sound_strike = gi.soundindex("tank/tnkatck5.wav");
+ sound_sight = gi.soundindex("tank/sight1.wav");
+
+ gi.soundindex("tank/tnkatck1.wav");
+ gi.soundindex("tank/tnkatk2a.wav");
+ gi.soundindex("tank/tnkatk2b.wav");
+ gi.soundindex("tank/tnkatk2c.wav");
+ gi.soundindex("tank/tnkatk2d.wav");
+ gi.soundindex("tank/tnkatk2e.wav");
+ gi.soundindex("tank/tnkatck3.wav");
+
+ if (Lib.strcmp(self.classname, "monster_tank_commander") == 0) {
+ self.health = 1000;
+ self.gib_health = -225;
+ } else {
+ self.health = 750;
+ self.gib_health = -200;
+ }
+
+ self.mass = 500;
+
+ self.pain = tank_pain;
+ self.die = tank_die;
+ self.monsterinfo.stand = tank_stand;
+ self.monsterinfo.walk = tank_walk;
+ self.monsterinfo.run = tank_run;
+ self.monsterinfo.dodge = null;
+ self.monsterinfo.attack = tank_attack;
+ self.monsterinfo.melee = null;
+ self.monsterinfo.sight = tank_sight;
+ self.monsterinfo.idle = tank_idle;
+
+ gi.linkentity(self);
+
+ self.monsterinfo.currentmove = tank_move_stand;
+ self.monsterinfo.scale = MODEL_SCALE;
+
+ walkmonster_start.think(self);
+
+ if (Lib.strcmp(self.classname, "monster_tank_commander") == 0)
+ self.s.skinnum = 2;
+ return true;
+ }
+ };
+
+}
diff --git a/src/jake2/game/Monster.java b/src/jake2/game/Monster.java
new file mode 100644
index 0000000..0b28f4c
--- /dev/null
+++ b/src/jake2/game/Monster.java
@@ -0,0 +1,368 @@
+/*
+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 17.12.2003 by RST.
+// $Id: Monster.java,v 1.1 2004-07-07 19:59:21 hzi Exp $
+
+package jake2.game;
+
+import jake2.Defines;
+import jake2.client.M;
+import jake2.qcommon.CM;
+import jake2.qcommon.Com;
+import jake2.util.*;
+
+import java.util.*;
+
+public class Monster extends GameAI{
+
+ // FIXME mosnters should call these with a totally accurate direction
+ // and we can mess it up based on skill. Spread should be for normal
+ // and we can tighten or loosen based on skill. We could muck with
+ // the damages too, but I'm not sure that's such a good idea.
+ public static void monster_fire_bullet(
+ edict_t self,
+ float[] start,
+ float[] dir,
+ int damage,
+ int kick,
+ int hspread,
+ int vspread,
+ int flashtype) {
+ Fire.fire_bullet(self, start, dir, damage, kick, hspread, vspread, Defines.MOD_UNKNOWN);
+
+ GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
+ GameBase.gi.WriteShort(self.index);
+ GameBase.gi.WriteByte(flashtype);
+ GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
+ }
+ /** The Moster fires the shotgun. */
+ public static void monster_fire_shotgun(
+ edict_t self,
+ float[] start,
+ float[] aimdir,
+ int damage,
+ int kick,
+ int hspread,
+ int vspread,
+ int count,
+ int flashtype) {
+ Fire.fire_shotgun(self, start, aimdir, damage, kick, hspread, vspread, count, Defines.MOD_UNKNOWN);
+
+ GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
+ GameBase.gi.WriteShort(self.index);
+ GameBase.gi.WriteByte(flashtype);
+ GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
+ }
+ /** The Moster fires the blaster. */
+ public static void monster_fire_blaster(
+ edict_t self,
+ float[] start,
+ float[] dir,
+ int damage,
+ int speed,
+ int flashtype,
+ int effect) {
+ Fire.fire_blaster(self, start, dir, damage, speed, effect, false);
+
+ GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
+ GameBase.gi.WriteShort(self.index);
+ GameBase.gi.WriteByte(flashtype);
+ GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
+ }
+ /** The Moster fires the grenade. */
+ public static void monster_fire_grenade(edict_t self, float[] start, float[] aimdir, int damage, int speed, int flashtype) {
+ Fire.fire_grenade(self, start, aimdir, damage, speed, 2.5f, damage + 40);
+
+ GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
+ GameBase.gi.WriteShort(self.index);
+ GameBase.gi.WriteByte(flashtype);
+ GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
+ }
+ /** The Moster fires the rocket. */
+ public static void monster_fire_rocket(edict_t self, float[] start, float[] dir, int damage, int speed, int flashtype) {
+ Fire.fire_rocket(self, start, dir, damage, speed, damage + 20, damage);
+
+ GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
+ GameBase.gi.WriteShort(self.index);
+ GameBase.gi.WriteByte(flashtype);
+ GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
+ }
+ /** The Moster fires the railgun. */
+ public static void monster_fire_railgun(edict_t self, float[] start, float[] aimdir, int damage, int kick, int flashtype) {
+ Fire.fire_rail(self, start, aimdir, damage, kick);
+
+ GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
+ GameBase.gi.WriteShort(self.index);
+ GameBase.gi.WriteByte(flashtype);
+ GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
+ }
+ /** The Moster fires the bfg. */
+ public static void monster_fire_bfg(
+ edict_t self,
+ float[] start,
+ float[] aimdir,
+ int damage,
+ int speed,
+ int kick,
+ float damage_radius,
+ int flashtype) {
+ Fire.fire_bfg(self, start, aimdir, damage, speed, damage_radius);
+
+ GameBase.gi.WriteByte(Defines.svc_muzzleflash2);
+ GameBase.gi.WriteShort(self.index);
+ GameBase.gi.WriteByte(flashtype);
+ GameBase.gi.multicast(start, Defines.MULTICAST_PVS);
+ }
+ /*
+ ================
+ monster_death_use
+
+ When a monster dies, it fires all of its targets with the current
+ enemy as activator.
+ ================
+ */
+ public static void monster_death_use(edict_t self) {
+ self.flags &= ~(Defines.FL_FLY | Defines.FL_SWIM);
+ self.monsterinfo.aiflags &= Defines.AI_GOOD_GUY;
+
+ if (self.item != null) {
+ GameUtil.Drop_Item(self, self.item);
+ self.item = null;
+ }
+
+ if (self.deathtarget != null)
+ self.target = self.deathtarget;
+
+ if (self.target == null)
+ return;
+
+ GameUtil.G_UseTargets(self, self.enemy);
+ }
+ // ============================================================================
+ public static boolean monster_start(edict_t self) {
+
+ if (GameBase.deathmatch.value != 0) {
+ GameUtil.G_FreeEdict(self);
+ return false;
+ }
+
+ if ((self.spawnflags & 4) != 0 && 0 == (self.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) {
+ self.spawnflags &= ~4;
+ self.spawnflags |= 1;
+ // gi.dprintf("fixed spawnflags on %s at %s\n", self.classname, vtos(self.s.origin));
+ }
+
+ if (0 == (self.monsterinfo.aiflags & Defines.AI_GOOD_GUY))
+ GameBase.level.total_monsters++;
+
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+ self.svflags |= Defines.SVF_MONSTER;
+ self.s.renderfx |= Defines.RF_FRAMELERP;
+ self.takedamage = Defines.DAMAGE_AIM;
+ self.air_finished = GameBase.level.time + 12;
+ self.use = GameUtil.monster_use;
+ self.max_health = self.health;
+ self.clipmask = Defines.MASK_MONSTERSOLID;
+
+ self.s.skinnum = 0;
+ self.deadflag = Defines.DEAD_NO;
+ self.svflags &= ~Defines.SVF_DEADMONSTER;
+
+ if (null == self.monsterinfo.checkattack)
+ self.monsterinfo.checkattack = GameUtil.M_CheckAttack;
+ Math3D.VectorCopy(self.s.origin, self.s.old_origin);
+
+ if (GameBase.st.item != null) {
+ self.item = GameUtil.FindItemByClassname(GameBase.st.item);
+ if (self.item != null)
+ GameBase.gi.dprintf(self.classname + " at " + Lib.vtos(self.s.origin) + " has bad item: " + GameBase.st.item + "\n");
+ }
+
+ // randomize what frame they start on
+ if (self.monsterinfo.currentmove != null)
+ self.s.frame =
+ self.monsterinfo.currentmove.firstframe
+ + (Lib.rand() % (self.monsterinfo.currentmove.lastframe - self.monsterinfo.currentmove.firstframe + 1));
+
+ return true;
+ }
+
+
+ public static void monster_start_go(edict_t self) {
+ float[] v = { 0, 0, 0 };
+
+ if (self.health <= 0)
+ return;
+
+ // check for target to combat_point and change to combattarget
+ if (self.target != null) {
+ boolean notcombat;
+ boolean fixup;
+ edict_t target = null;
+ notcombat = false;
+ fixup = false;
+
+ EdictIterator edit = null;
+
+ /*
+ if (true) {
+ Com.Printf("all entities:\n");
+
+ for (int n = 0; n < Game.globals.num_edicts; n++) {
+ edict_t ent = GameBase.g_edicts[n];
+ Com.Printf(
+ "|%4i | %25s |%8.2f|%8.2f|%8.2f||%8.2f|%8.2f|%8.2f||%8.2f|%8.2f|%8.2f|\n",
+ new Vargs().add(n).add(ent.classname).
+ add(ent.s.origin[0]).add(ent.s.origin[1]).add(ent.s.origin[2])
+ .add(ent.mins[0]).add(ent.mins[1]).add(ent.mins[2])
+ .add(ent.maxs[0]).add(ent.maxs[1]).add(ent.maxs[2]));
+ }
+ }
+
+ sleep(10);
+ */
+
+ while ((edit = GameBase.G_Find(edit, GameBase.findByTarget, self.target)) != null) {
+ target = edit.o;
+ if (Lib.strcmp(target.classname, "point_combat") == 0) {
+ self.combattarget = self.target;
+ fixup = true;
+ }
+ else {
+ notcombat = true;
+ }
+ }
+ if (notcombat && self.combattarget != null)
+ GameBase.gi.dprintf(self.classname + " at " + Lib.vtos(self.s.origin) + " has target with mixed types\n");
+ if (fixup)
+ self.target = null;
+ }
+
+ // validate combattarget
+ if (self.combattarget != null) {
+ edict_t target = null;
+
+ EdictIterator edit = null;
+ while ((edit = GameBase.G_Find(edit, GameBase.findByTarget, self.combattarget)) != null) {
+ target = edit.o;
+
+ if (Lib.strcmp(target.classname, "point_combat") != 0) {
+ GameBase.gi.dprintf(
+ self.classname
+ + " at "
+ + Lib.vtos(self.s.origin)
+ + " has bad combattarget "
+ + self.combattarget
+ + " : "
+ + target.classname
+ + " at "
+ + Lib.vtos(target.s.origin));
+ }
+ }
+ }
+
+ if (self.target != null) {
+ self.goalentity = self.movetarget = GameBase.G_PickTarget(self.target);
+ if (null == self.movetarget) {
+ GameBase.gi.dprintf(self.classname + " can't find target " + self.target + " at " + Lib.vtos(self.s.origin) + "\n");
+ self.target = null;
+ self.monsterinfo.pausetime = 100000000;
+ self.monsterinfo.stand.think(self);
+ }
+ else if (Lib.strcmp(self.movetarget.classname, "path_corner") == 0) {
+ Math3D.VectorSubtract(self.goalentity.s.origin, self.s.origin, v);
+ self.ideal_yaw = self.s.angles[Defines.YAW] = Math3D.vectoyaw(v);
+ self.monsterinfo.walk.think(self);
+ self.target = null;
+ }
+ else {
+ self.goalentity = self.movetarget = null;
+ self.monsterinfo.pausetime = 100000000;
+ self.monsterinfo.stand.think(self);
+ }
+ }
+ else {
+ self.monsterinfo.pausetime = 100000000;
+ self.monsterinfo.stand.think(self);
+ }
+
+ self.think = Monster.monster_think;
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+ }
+ public static EntThinkAdapter monster_think = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ M.M_MoveFrame(self);
+ if (self.linkcount != self.monsterinfo.linkcount) {
+ self.monsterinfo.linkcount = self.linkcount;
+ M.M_CheckGround(self);
+ }
+ M.M_CatagorizePosition(self);
+ M.M_WorldEffects(self);
+ M.M_SetEffects(self);
+ return true;
+ }
+ };
+ public static EntThinkAdapter monster_triggered_spawn = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ self.s.origin[2] += 1;
+ GameUtil.KillBox(self);
+
+ self.solid = Defines.SOLID_BBOX;
+ self.movetype = Defines.MOVETYPE_STEP;
+ self.svflags &= ~Defines.SVF_NOCLIENT;
+ self.air_finished = GameBase.level.time + 12;
+ GameBase.gi.linkentity(self);
+
+ Monster.monster_start_go(self);
+
+ if (self.enemy != null && 0 == (self.spawnflags & 1) && 0 == (self.enemy.flags & Defines.FL_NOTARGET)) {
+ GameUtil.FoundTarget(self);
+ }
+ else {
+ self.enemy = null;
+ }
+ return true;
+ }
+ };
+ // we have a one frame delay here so we don't telefrag the guy who activated us
+ public static EntUseAdapter monster_triggered_spawn_use = new EntUseAdapter() {
+
+ public void use(edict_t self, edict_t other, edict_t activator) {
+ self.think = monster_triggered_spawn;
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+ if (activator.client != null)
+ self.enemy = activator;
+ self.use = GameUtil.monster_use;
+ }
+ };
+ public static EntThinkAdapter monster_triggered_start = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.solid = Defines.SOLID_NOT;
+ self.movetype = Defines.MOVETYPE_NONE;
+ self.svflags |= Defines.SVF_NOCLIENT;
+ self.nextthink = 0;
+ self.use = monster_triggered_spawn_use;
+ return true;
+ }
+ };
+}
diff --git a/src/jake2/game/PlayerClient.java b/src/jake2/game/PlayerClient.java
new file mode 100644
index 0000000..5cf627d
--- /dev/null
+++ b/src/jake2/game/PlayerClient.java
@@ -0,0 +1,1566 @@
+/*
+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: PlayerClient.java,v 1.1 2004-07-07 19:59:22 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.game.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class PlayerClient extends PlayerHud {
+
+ //
+ // Gross, ugly, disgustuing hack section
+ //
+
+ // this function is an ugly as hell hack to fix some map flaws
+ //
+ // the coop spawn spots on some maps are SNAFU. There are coop spots
+ // with the wrong targetname as well as spots with no name at all
+ //
+ // we use carnal knowledge of the maps to fix the coop spot targetnames to match
+ // that of the nearest named single player spot
+
+ static EntThinkAdapter SP_FixCoopSpots = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ edict_t spot;
+ float[] d = { 0, 0, 0 };
+
+ spot = null;
+ EdictIterator es = null;
+
+ while (true) {
+ es = G_Find(es, findByClass, "info_player_start");
+ spot = es.o;
+ if (spot == null)
+ return true;
+ if (spot.targetname == null)
+ continue;
+ VectorSubtract(self.s.origin, spot.s.origin, d);
+ if (VectorLength(d) < 384) {
+ if ((self.targetname == null) || Q_stricmp(self.targetname, spot.targetname) != 0) {
+ // gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self.classname, vtos(self.s.origin), self.targetname, spot.targetname);
+ self.targetname = spot.targetname;
+ }
+ return true;
+ }
+ }
+ return true;
+ }
+ };
+
+ // now if that one wasn't ugly enough for you then try this one on for size
+ // some maps don't have any coop spots at all, so we need to create them
+ // where they should have been
+
+ static EntThinkAdapter SP_CreateCoopSpots = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ edict_t spot;
+
+ if (Q_stricmp(level.mapname, "security") == 0) {
+ spot = G_Spawn();
+ spot.classname = "info_player_coop";
+ spot.s.origin[0] = 188 - 64;
+ spot.s.origin[1] = -164;
+ spot.s.origin[2] = 80;
+ spot.targetname = "jail3";
+ spot.s.angles[1] = 90;
+
+ spot = G_Spawn();
+ spot.classname = "info_player_coop";
+ spot.s.origin[0] = 188 + 64;
+ spot.s.origin[1] = -164;
+ spot.s.origin[2] = 80;
+ spot.targetname = "jail3";
+ spot.s.angles[1] = 90;
+
+ spot = G_Spawn();
+ spot.classname = "info_player_coop";
+ spot.s.origin[0] = 188 + 128;
+ spot.s.origin[1] = -164;
+ spot.s.origin[2] = 80;
+ spot.targetname = "jail3";
+ spot.s.angles[1] = 90;
+ }
+ return true;
+ }
+ };
+
+ /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
+ The normal starting point for a level.
+ */
+ public static void SP_info_player_start(edict_t self) {
+ if (coop.value == 0)
+ return;
+ if (Q_stricmp(level.mapname, "security") == 0) {
+ // invoke one of our gross, ugly, disgusting hacks
+ self.think = SP_CreateCoopSpots;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ }
+
+ /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
+ potential spawning position for deathmatch games
+ */
+ public static void SP_info_player_deathmatch(edict_t self) {
+ if (0 == deathmatch.value) {
+ G_FreeEdict(self);
+ return;
+ }
+ SP_misc_teleporter_dest.think(self);
+ }
+
+ /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
+ potential spawning position for coop games
+ */
+
+ public static void SP_info_player_coop(edict_t self) {
+ if (0 == coop.value) {
+ G_FreeEdict(self);
+ return;
+ }
+
+ if ((Q_stricmp(level.mapname, "jail2") == 0)
+ || (Q_stricmp(level.mapname, "jail4") == 0)
+ || (Q_stricmp(level.mapname, "mine1") == 0)
+ || (Q_stricmp(level.mapname, "mine2") == 0)
+ || (Q_stricmp(level.mapname, "mine3") == 0)
+ || (Q_stricmp(level.mapname, "mine4") == 0)
+ || (Q_stricmp(level.mapname, "lab") == 0)
+ || (Q_stricmp(level.mapname, "boss1") == 0)
+ || (Q_stricmp(level.mapname, "fact3") == 0)
+ || (Q_stricmp(level.mapname, "biggun") == 0)
+ || (Q_stricmp(level.mapname, "space") == 0)
+ || (Q_stricmp(level.mapname, "command") == 0)
+ || (Q_stricmp(level.mapname, "power2") == 0)
+ || (Q_stricmp(level.mapname, "strike") == 0)) {
+ // invoke one of our gross, ugly, disgusting hacks
+ self.think = SP_FixCoopSpots;
+ self.nextthink = level.time + FRAMETIME;
+ }
+ }
+
+ /*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
+ The deathmatch intermission point will be at one of these
+ Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw. 'pitch yaw roll'
+ */
+ public static void SP_info_player_intermission() {
+ }
+
+ //=======================================================================
+
+ static EntPainAdapter player_pain = new EntPainAdapter() {
+ public void pain(edict_t self, edict_t other, float kick, int damage) {
+ // player pain is handled at the end of the frame in P_DamageFeedback
+ }
+ };
+
+ public static void ClientObituary(edict_t self, edict_t inflictor, edict_t attacker) {
+ int mod;
+ String message;
+ String message2;
+ boolean ff;
+
+ if (coop.value != 0 && attacker.client != null)
+ meansOfDeath |= MOD_FRIENDLY_FIRE;
+
+ if (deathmatch.value != 0 || coop.value != 0) {
+ ff = (meansOfDeath & MOD_FRIENDLY_FIRE) != 0;
+ mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
+ message = null;
+ message2 = "";
+
+ switch (mod) {
+ case MOD_SUICIDE :
+ message = "suicides";
+ break;
+ case MOD_FALLING :
+ message = "cratered";
+ break;
+ case MOD_CRUSH :
+ message = "was squished";
+ break;
+ case MOD_WATER :
+ message = "sank like a rock";
+ break;
+ case MOD_SLIME :
+ message = "melted";
+ break;
+ case MOD_LAVA :
+ message = "does a back flip into the lava";
+ break;
+ case MOD_EXPLOSIVE :
+ case MOD_BARREL :
+ message = "blew up";
+ break;
+ case MOD_EXIT :
+ message = "found a way out";
+ break;
+ case MOD_TARGET_LASER :
+ message = "saw the light";
+ break;
+ case MOD_TARGET_BLASTER :
+ message = "got blasted";
+ break;
+ case MOD_BOMB :
+ case MOD_SPLASH :
+ case MOD_TRIGGER_HURT :
+ message = "was in the wrong place";
+ break;
+ }
+ if (attacker == self) {
+ switch (mod) {
+ case MOD_HELD_GRENADE :
+ message = "tried to put the pin back in";
+ break;
+ case MOD_HG_SPLASH :
+ case MOD_G_SPLASH :
+ if (IsNeutral(self))
+ message = "tripped on its own grenade";
+ else if (IsFemale(self))
+ message = "tripped on her own grenade";
+ else
+ message = "tripped on his own grenade";
+ break;
+ case MOD_R_SPLASH :
+ if (IsNeutral(self))
+ message = "blew itself up";
+ else if (IsFemale(self))
+ message = "blew herself up";
+ else
+ message = "blew himself up";
+ break;
+ case MOD_BFG_BLAST :
+ message = "should have used a smaller gun";
+ break;
+ default :
+ if (IsNeutral(self))
+ message = "killed itself";
+ else if (IsFemale(self))
+ message = "killed herself";
+ else
+ message = "killed himself";
+ break;
+ }
+ }
+ if (message != null) {
+ gi.bprintf(PRINT_MEDIUM, self.client.pers.netname + " " + message + ".\n");
+ if (deathmatch.value != 0)
+ self.client.resp.score--;
+ self.enemy = null;
+ return;
+ }
+
+ self.enemy = attacker;
+ if (attacker != null && attacker.client != null) {
+ switch (mod) {
+ case MOD_BLASTER :
+ message = "was blasted by";
+ break;
+ case MOD_SHOTGUN :
+ message = "was gunned down by";
+ break;
+ case MOD_SSHOTGUN :
+ message = "was blown away by";
+ message2 = "'s super shotgun";
+ break;
+ case MOD_MACHINEGUN :
+ message = "was machinegunned by";
+ break;
+ case MOD_CHAINGUN :
+ message = "was cut in half by";
+ message2 = "'s chaingun";
+ break;
+ case MOD_GRENADE :
+ message = "was popped by";
+ message2 = "'s grenade";
+ break;
+ case MOD_G_SPLASH :
+ message = "was shredded by";
+ message2 = "'s shrapnel";
+ break;
+ case MOD_ROCKET :
+ message = "ate";
+ message2 = "'s rocket";
+ break;
+ case MOD_R_SPLASH :
+ message = "almost dodged";
+ message2 = "'s rocket";
+ break;
+ case MOD_HYPERBLASTER :
+ message = "was melted by";
+ message2 = "'s hyperblaster";
+ break;
+ case MOD_RAILGUN :
+ message = "was railed by";
+ break;
+ case MOD_BFG_LASER :
+ message = "saw the pretty lights from";
+ message2 = "'s BFG";
+ break;
+ case MOD_BFG_BLAST :
+ message = "was disintegrated by";
+ message2 = "'s BFG blast";
+ break;
+ case MOD_BFG_EFFECT :
+ message = "couldn't hide from";
+ message2 = "'s BFG";
+ break;
+ case MOD_HANDGRENADE :
+ message = "caught";
+ message2 = "'s handgrenade";
+ break;
+ case MOD_HG_SPLASH :
+ message = "didn't see";
+ message2 = "'s handgrenade";
+ break;
+ case MOD_HELD_GRENADE :
+ message = "feels";
+ message2 = "'s pain";
+ break;
+ case MOD_TELEFRAG :
+ message = "tried to invade";
+ message2 = "'s personal space";
+ break;
+ }
+ if (message != null) {
+ gi.bprintf(
+ PRINT_MEDIUM,
+ self.client.pers.netname
+ + " "
+ + message
+ + " "
+ + attacker.client.pers.netname
+ + " "
+ + message2
+ + "\n");
+ if (deathmatch.value != 0) {
+ if (ff)
+ attacker.client.resp.score--;
+ else
+ attacker.client.resp.score++;
+ }
+ return;
+ }
+ }
+ }
+
+ gi.bprintf(PRINT_MEDIUM, self.client.pers.netname + " died.\n");
+ if (deathmatch.value != 0)
+ self.client.resp.score--;
+ }
+
+ /*
+ ==================
+ player_die
+ ==================
+ */
+
+ //=======================================================================
+
+ /*
+ ==============
+ InitClientPersistant
+
+ This is only called when the game first initializes in single player,
+ but is called after each death and level change in deathmatch
+ ==============
+ */
+ public static void InitClientPersistant(gclient_t client) {
+ gitem_t item;
+
+ //memset(& client.pers, 0, sizeof(client.pers));
+ client.pers = new client_persistant_t();
+
+ item = FindItem("Blaster");
+ client.pers.selected_item = ITEM_INDEX(item);
+ client.pers.inventory[client.pers.selected_item] = 1;
+
+ client.pers.weapon = item;
+
+ client.pers.health = 100;
+ client.pers.max_health = 100;
+
+ client.pers.max_bullets = 200;
+ client.pers.max_shells = 100;
+ client.pers.max_rockets = 50;
+ client.pers.max_grenades = 50;
+ client.pers.max_cells = 200;
+ client.pers.max_slugs = 50;
+
+ client.pers.connected = true;
+ }
+
+ public static void InitClientResp(gclient_t client) {
+ //memset(& client.resp, 0, sizeof(client.resp));
+ client.resp.clear(); // ok.
+ client.resp.enterframe = level.framenum;
+ client.resp.coop_respawn = client.pers.getClone();
+ }
+
+ /*
+ ==================
+ SaveClientData
+
+ Some information that should be persistant, like health,
+ is still stored in the edict structure, so it needs to
+ be mirrored out to the client structure before all the
+ edicts are wiped.
+ ==================
+ */
+ public static void SaveClientData() {
+ int i;
+ edict_t ent;
+
+ for (i = 0; i < game.maxclients; i++) {
+ ent = g_edicts[1 + i];
+ if (!ent.inuse)
+ continue;
+ game.clients[i].pers.health = ent.health;
+ game.clients[i].pers.max_health = ent.max_health;
+ game.clients[i].pers.savedFlags = (ent.flags & (FL_GODMODE | FL_NOTARGET | FL_POWER_ARMOR));
+ if (coop.value != 0)
+ game.clients[i].pers.score = ent.client.resp.score;
+ }
+ }
+
+ public static void FetchClientEntData(edict_t ent) {
+ ent.health = ent.client.pers.health;
+ ent.max_health = ent.client.pers.max_health;
+ ent.flags |= ent.client.pers.savedFlags;
+ if (coop.value != 0)
+ ent.client.resp.score = ent.client.pers.score;
+ }
+
+ /*
+ =======================================================================
+
+ SelectSpawnPoint
+
+ =======================================================================
+ */
+
+ /*
+ ================
+ PlayersRangeFromSpot
+
+ Returns the distance to the nearest player from the given spot
+ ================
+ */
+ static float PlayersRangeFromSpot(edict_t spot) {
+ edict_t player;
+ float bestplayerdistance;
+ float[] v = { 0, 0, 0 };
+ int n;
+ float playerdistance;
+
+ bestplayerdistance = 9999999;
+
+ for (n = 1; n <= maxclients.value; n++) {
+ player = g_edicts[n];
+
+ if (!player.inuse)
+ continue;
+
+ if (player.health <= 0)
+ continue;
+
+ VectorSubtract(spot.s.origin, player.s.origin, v);
+ playerdistance = VectorLength(v);
+
+ if (playerdistance < bestplayerdistance)
+ bestplayerdistance = playerdistance;
+ }
+
+ return bestplayerdistance;
+ }
+
+ /*
+ ================
+ SelectRandomDeathmatchSpawnPoint
+
+ go to a random point, but NOT the two points closest
+ to other players
+ ================
+ */
+ public static edict_t SelectRandomDeathmatchSpawnPoint() {
+ edict_t spot, spot1, spot2;
+ int count = 0;
+ int selection;
+ float range, range1, range2;
+
+ spot = null;
+ range1 = range2 = 99999;
+ spot1 = spot2 = null;
+
+ EdictIterator es = null;
+
+ while ((es = G_Find(es, findByClass, "info_player_deathmatch")) != null) {
+ spot = es.o;
+ count++;
+ range = PlayersRangeFromSpot(spot);
+ if (range < range1) {
+ range1 = range;
+ spot1 = spot;
+ }
+ else if (range < range2) {
+ range2 = range;
+ spot2 = spot;
+ }
+ }
+
+ if (count == 0)
+ return null;
+
+ if (count <= 2) {
+ spot1 = spot2 = null;
+ }
+ else
+ count -= 2;
+
+ selection = rand() % count;
+
+ spot = null;
+ es = null;
+ do {
+ es = G_Find(es, findByClass, "info_player_deathmatch");
+ spot = es.o;
+ if (spot == spot1 || spot == spot2)
+ selection++;
+ }
+ while (selection-- > 0);
+
+ return spot;
+ }
+
+ /*
+ ================
+ SelectFarthestDeathmatchSpawnPoint
+
+ ================
+ */
+ static edict_t SelectFarthestDeathmatchSpawnPoint() {
+ edict_t bestspot;
+ float bestdistance, bestplayerdistance;
+ edict_t spot;
+
+ spot = null;
+ bestspot = null;
+ bestdistance = 0;
+
+ EdictIterator es = null;
+ while ((es = G_Find(es, findByClass, "info_player_deathmatch")).o != null) {
+ spot = es.o;
+ bestplayerdistance = PlayersRangeFromSpot(spot);
+
+ if (bestplayerdistance > bestdistance) {
+ bestspot = spot;
+ bestdistance = bestplayerdistance;
+ }
+ }
+
+ if (bestspot != null) {
+ return bestspot;
+ }
+
+ // if there is a player just spawned on each and every start spot
+ // we have no choice to turn one into a telefrag meltdown
+ spot = G_Find(null, findByClass, "info_player_deathmatch").o;
+
+ return spot;
+ }
+
+ public static edict_t SelectDeathmatchSpawnPoint() {
+ if (0 != ((int) (dmflags.value) & DF_SPAWN_FARTHEST))
+ return SelectFarthestDeathmatchSpawnPoint();
+ else
+ return SelectRandomDeathmatchSpawnPoint();
+ }
+
+ public static edict_t SelectCoopSpawnPoint(edict_t ent) {
+ int index;
+ edict_t spot = null;
+ String target;
+
+ //index = ent.client - game.clients;
+ index = ent.client.index;
+
+ // player 0 starts in normal player spawn point
+ if (index == 0)
+ return null;
+
+ spot = null;
+ EdictIterator es = null;
+
+ // assume there are four coop spots at each spawnpoint
+ while (true) {
+
+ spot = (es = G_Find(es, findByClass, "info_player_coop")).o;
+ if (spot == null)
+ return null; // we didn't have enough...
+
+ target = spot.targetname;
+ if (target == null)
+ target = "";
+ if (Q_stricmp(game.spawnpoint, target) == 0) { // this is a coop spawn point for one of the clients here
+ index--;
+ if (0 == index)
+ return spot; // this is it
+ }
+ }
+
+ return spot;
+ }
+
+ /*
+ ===========
+ SelectSpawnPoint
+
+ Chooses a player start, deathmatch start, coop start, etc
+ ============
+ */
+ public static void SelectSpawnPoint(edict_t ent, float[] origin, float[] angles) {
+ edict_t spot = null;
+
+ if (deathmatch.value != 0)
+ spot = SelectDeathmatchSpawnPoint();
+ else if (coop.value != 0)
+ spot = SelectCoopSpawnPoint(ent);
+
+ EdictIterator es = null;
+ // find a single player start spot
+ if (null == spot) {
+ while ((es = G_Find(es, findByClass, "info_player_start")) != null) {
+ spot = es.o;
+
+ if (game.spawnpoint.length() == 0 && spot.targetname == null)
+ break;
+
+ if (game.spawnpoint.length() == 0 || spot.targetname == null)
+ continue;
+
+ if (Q_stricmp(game.spawnpoint, spot.targetname) == 0)
+ break;
+ }
+
+ if (null == spot) {
+ if (game.spawnpoint.length() == 0) { // there wasn't a spawnpoint without a target, so use any
+ spot = (es = G_Find(es, findByClass, "info_player_start")).o;
+ }
+ if (null == spot)
+ gi.error("Couldn't find spawn point " + game.spawnpoint + "\n");
+ }
+ }
+
+ VectorCopy(spot.s.origin, origin);
+ origin[2] += 9;
+ VectorCopy(spot.s.angles, angles);
+ }
+
+ //======================================================================
+
+ public static void InitBodyQue() {
+ int i;
+ edict_t ent;
+
+ level.body_que = 0;
+ for (i = 0; i < BODY_QUEUE_SIZE; i++) {
+ ent = G_Spawn();
+ ent.classname = "bodyque";
+ }
+ }
+
+ static EntDieAdapter body_die = new EntDieAdapter() {
+ public void die(edict_t self, edict_t inflictor, edict_t attacker, int damage, float[] point) {
+
+ int n;
+
+ if (self.health < -40) {
+ gi.sound(self, CHAN_BODY, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
+ for (n = 0; n < 4; n++)
+ ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
+ self.s.origin[2] -= 48;
+ ThrowClientHead(self, damage);
+ self.takedamage = DAMAGE_NO;
+ }
+ }
+ };
+
+ public static void CopyToBodyQue(edict_t ent) {
+ edict_t body;
+
+ // grab a body que and cycle to the next one
+ int i = (int) maxclients.value + level.body_que + 1;
+ body = g_edicts[i];
+ level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE;
+
+ // FIXME: send an effect on the removed body
+
+ gi.unlinkentity(ent);
+
+ gi.unlinkentity(body);
+ body.s = ent.s.getClone();
+
+ body.s.number = body.index;
+
+ body.svflags = ent.svflags;
+ VectorCopy(ent.mins, body.mins);
+ VectorCopy(ent.maxs, body.maxs);
+ VectorCopy(ent.absmin, body.absmin);
+ VectorCopy(ent.absmax, body.absmax);
+ VectorCopy(ent.size, body.size);
+ body.solid = ent.solid;
+ body.clipmask = ent.clipmask;
+ body.owner = ent.owner;
+ body.movetype = ent.movetype;
+
+ body.die = body_die;
+ body.takedamage = DAMAGE_YES;
+
+ gi.linkentity(body);
+ }
+
+ public static void respawn(edict_t self) {
+ if (deathmatch.value != 0 || coop.value != 0) {
+ // spectator's don't leave bodies
+ if (self.movetype != MOVETYPE_NOCLIP)
+ CopyToBodyQue(self);
+ self.svflags &= ~SVF_NOCLIENT;
+ PutClientInServer(self);
+
+ // add a teleportation effect
+ self.s.event = EV_PLAYER_TELEPORT;
+
+ // hold in place briefly
+ self.client.ps.pmove.pm_flags = PMF_TIME_TELEPORT;
+ self.client.ps.pmove.pm_time = 14;
+
+ self.client.respawn_time = level.time;
+
+ return;
+ }
+
+ // restart the entire server
+ gi.AddCommandString("menu_loadgame\n");
+ }
+
+ private static boolean passwdOK(String i1, String i2) {
+ if (i1.length() != 0 && !i1.equals("none") && !i1.equals(i2))
+ return false;
+ return true;
+ }
+
+ /*
+ * only called when pers.spectator changes
+ * note that resp.spectator should be the opposite of pers.spectator here
+ */
+ public static void spectator_respawn(edict_t ent) {
+ int i, numspec;
+
+ // if the user wants to become a spectator, make sure he doesn't
+ // exceed max_spectators
+
+ if (ent.client.pers.spectator) {
+ String value = Info.Info_ValueForKey(ent.client.pers.userinfo, "spectator");
+
+ if (!passwdOK(spectator_password.string, value)) {
+ gi.cprintf(ent, PRINT_HIGH, "Spectator password incorrect.\n");
+ ent.client.pers.spectator = false;
+ gi.WriteByte(svc_stufftext);
+ gi.WriteString("spectator 0\n");
+ gi.unicast(ent, true);
+ return;
+ }
+
+ // count spectators
+ for (i = 1, numspec = 0; i <= maxclients.value; i++)
+ if (g_edicts[i].inuse && g_edicts[i].client.pers.spectator)
+ numspec++;
+
+ if (numspec >= maxspectators.value) {
+ gi.cprintf(ent, PRINT_HIGH, "Server spectator limit is full.");
+ ent.client.pers.spectator = false;
+ // reset his spectator var
+ gi.WriteByte(svc_stufftext);
+ gi.WriteString("spectator 0\n");
+ gi.unicast(ent, true);
+ return;
+ }
+ }
+ else {
+ // he was a spectator and wants to join the game
+ // he must have the right password
+ String value = Info.Info_ValueForKey(ent.client.pers.userinfo, "password");
+ if (!passwdOK(spectator_password.string, value)) {
+ gi.cprintf(ent, PRINT_HIGH, "Password incorrect.\n");
+ ent.client.pers.spectator = true;
+ gi.WriteByte(svc_stufftext);
+ gi.WriteString("spectator 1\n");
+ gi.unicast(ent, true);
+ return;
+ }
+ }
+
+ // clear client on respawn
+ ent.client.resp.score = ent.client.pers.score = 0;
+
+ ent.svflags &= ~SVF_NOCLIENT;
+ PutClientInServer(ent);
+
+ // add a teleportation effect
+ if (!ent.client.pers.spectator) {
+ // send effect
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+
+ gi.WriteByte(MZ_LOGIN);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ // hold in place briefly
+ ent.client.ps.pmove.pm_flags = PMF_TIME_TELEPORT;
+ ent.client.ps.pmove.pm_time = 14;
+ }
+
+ ent.client.respawn_time = level.time;
+
+ if (ent.client.pers.spectator)
+ gi.bprintf(PRINT_HIGH, ent.client.pers.netname + " has moved to the sidelines\n");
+ else
+ gi.bprintf(PRINT_HIGH, ent.client.pers.netname + " joined the game\n");
+ }
+
+ //==============================================================
+
+ /*
+ ===========
+ PutClientInServer
+
+ Called when a player connects to a server or respawns in
+ a deathmatch.
+ ============
+ */
+ public static void PutClientInServer(edict_t ent) {
+ float[] mins = { -16, -16, -24 };
+ float[] maxs = { 16, 16, 32 };
+ int index;
+ float[] spawn_origin = { 0, 0, 0 }, spawn_angles = { 0, 0, 0 };
+ gclient_t client;
+ int i;
+ client_persistant_t saved;
+ client_respawn_t resp = new client_respawn_t();
+
+ // find a spawn point
+ // do it before setting health back up, so farthest
+ // ranging doesn't count this client
+ SelectSpawnPoint(ent, spawn_origin, spawn_angles);
+
+ index = ent.index - 1;
+ client = ent.client;
+
+ // deathmatch wipes most client data every spawn
+ if (deathmatch.value != 0) {
+ String userinfo;
+ //char userinfo[MAX_INFO_STRING];
+
+ resp = client.resp;
+ userinfo = client.pers.userinfo;
+
+ //memcpy(userinfo, client.pers.userinfo, sizeof(userinfo));
+ InitClientPersistant(client);
+ userinfo = ClientUserinfoChanged(ent, userinfo);
+ }
+ else if (coop.value != 0) {
+ // int n;
+ //char userinfo[MAX_INFO_STRING];
+ String userinfo;
+
+ resp = client.resp;
+ //memcpy(userinfo, client.pers.userinfo, sizeof(userinfo));
+ userinfo = client.pers.userinfo;
+ // this is kind of ugly, but it's how we want to handle keys in coop
+ // for (n = 0; n < game.num_items; n++)
+ // {
+ // if (itemlist[n].flags & IT_KEY)
+ // resp.coop_respawn.inventory[n] = client.pers.inventory[n];
+ // }
+ resp.coop_respawn.game_helpchanged = client.pers.game_helpchanged;
+ resp.coop_respawn.helpchanged = client.pers.helpchanged;
+ client.pers = resp.coop_respawn;
+ userinfo = ClientUserinfoChanged(ent, userinfo);
+ if (resp.score > client.pers.score)
+ client.pers.score = resp.score;
+ }
+ else {
+ //memset(& resp, 0, sizeof(resp));
+ resp.clear();
+ }
+
+ // clear everything but the persistant data
+ saved = client.pers;
+ //memset(client, 0, sizeof(* client));
+ client.clear();
+ client.pers = saved;
+ if (client.pers.health <= 0)
+ InitClientPersistant(client);
+ client.resp = resp;
+
+ // copy some data from the client to the entity
+ FetchClientEntData(ent);
+
+ // clear entity values
+ ent.groundentity = null;
+ ent.client = game.clients[index];
+ ent.takedamage = DAMAGE_AIM;
+ ent.movetype = MOVETYPE_WALK;
+ ent.viewheight = 22;
+ ent.inuse = true;
+ ent.classname = "player";
+ ent.mass = 200;
+ ent.solid = SOLID_BBOX;
+ ent.deadflag = DEAD_NO;
+ ent.air_finished = level.time + 12;
+ ent.clipmask = MASK_PLAYERSOLID;
+ ent.model = "players/male/tris.md2";
+ ent.pain = player_pain;
+ ent.die = player_die;
+ ent.waterlevel = 0;
+ ent.watertype = 0;
+ ent.flags &= ~FL_NO_KNOCKBACK;
+ ent.svflags &= ~SVF_DEADMONSTER;
+
+ VectorCopy(mins, ent.mins);
+ VectorCopy(maxs, ent.maxs);
+ VectorClear(ent.velocity);
+
+ // clear playerstate values
+ ent.client.ps.clear();
+ //memset(& ent.client.ps, 0, sizeof(client.ps));
+
+ client.ps.pmove.origin[0] = (short) (spawn_origin[0] * 8);
+ client.ps.pmove.origin[1] = (short) (spawn_origin[1] * 8);
+ client.ps.pmove.origin[2] = (short) (spawn_origin[2] * 8);
+
+ if (deathmatch.value != 0 && 0 != ((int) dmflags.value & DF_FIXED_FOV)) {
+ client.ps.fov = 90;
+ }
+ else {
+ client.ps.fov = atoi(Info.Info_ValueForKey(client.pers.userinfo, "fov"));
+ if (client.ps.fov < 1)
+ client.ps.fov = 90;
+ else if (client.ps.fov > 160)
+ client.ps.fov = 160;
+ }
+
+ client.ps.gunindex = gi.modelindex(client.pers.weapon.view_model);
+
+ // clear entity state values
+ ent.s.effects = 0;
+ ent.s.modelindex = 255; // will use the skin specified model
+ ent.s.modelindex2 = 255; // custom gun model
+ // sknum is player num and weapon number
+ // weapon number will be added in changeweapon
+ ent.s.skinnum = ent.index - 1;
+
+ ent.s.frame = 0;
+ VectorCopy(spawn_origin, ent.s.origin);
+ ent.s.origin[2] += 1; // make sure off ground
+ VectorCopy(ent.s.origin, ent.s.old_origin);
+
+ // set the delta angle
+ for (i = 0; i < 3; i++) {
+ client.ps.pmove.delta_angles[i] = (short) ANGLE2SHORT(spawn_angles[i] - client.resp.cmd_angles[i]);
+ }
+
+ ent.s.angles[PITCH] = 0;
+ ent.s.angles[YAW] = spawn_angles[YAW];
+ ent.s.angles[ROLL] = 0;
+ VectorCopy(ent.s.angles, client.ps.viewangles);
+ VectorCopy(ent.s.angles, client.v_angle);
+
+ // spawn a spectator
+ if (client.pers.spectator) {
+ client.chase_target = null;
+
+ client.resp.spectator = true;
+
+ ent.movetype = MOVETYPE_NOCLIP;
+ ent.solid = SOLID_NOT;
+ ent.svflags |= SVF_NOCLIENT;
+ ent.client.ps.gunindex = 0;
+ gi.linkentity(ent);
+ return;
+ }
+ else
+ client.resp.spectator = false;
+
+ if (!KillBox(ent)) { // could't spawn in?
+ }
+
+ gi.linkentity(ent);
+
+ // force the current weapon up
+ client.newweapon = client.pers.weapon;
+ ChangeWeapon(ent);
+ }
+
+ /*
+ =====================
+ ClientBeginDeathmatch
+
+ A client has just connected to the server in
+ deathmatch mode, so clear everything out before starting them.
+ =====================
+ */
+ public static void ClientBeginDeathmatch(edict_t ent) {
+ G_InitEdict(ent, ent.index);
+
+ InitClientResp(ent.client);
+
+ // locate ent at a spawn point
+ PutClientInServer(ent);
+
+ if (level.intermissiontime != 0) {
+ MoveClientToIntermission(ent);
+ }
+ else {
+ // send effect
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_LOGIN);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+ }
+
+ gi.bprintf(PRINT_HIGH, ent.client.pers.netname + " entered the game\n");
+
+ // make sure all view stuff is valid
+ PlayerView.ClientEndServerFrame(ent);
+ }
+
+ /*
+ ===========
+ ClientBegin
+
+ called when a client has finished connecting, and is ready
+ to be placed into the game. This will happen every level load.
+ ============
+ */
+ public static void ClientBegin(edict_t ent) {
+ int i;
+
+ //ent.client = game.clients + (ent - g_edicts - 1);
+ ent.client = game.clients[ent.index - 1];
+
+ if (deathmatch.value != 0) {
+ ClientBeginDeathmatch(ent);
+ return;
+ }
+
+ // if there is already a body waiting for us (a loadgame), just
+ // take it, otherwise spawn one from scratch
+ if (ent.inuse == true) {
+ // the client has cleared the client side viewangles upon
+ // connecting to the server, which is different than the
+ // state when the game is saved, so we need to compensate
+ // with deltaangles
+ for (i = 0; i < 3; i++)
+ ent.client.ps.pmove.delta_angles[i] = (short) ANGLE2SHORT(ent.client.ps.viewangles[i]);
+ }
+ else {
+ // a spawn point will completely reinitialize the entity
+ // except for the persistant data that was initialized at
+ // ClientConnect() time
+ G_InitEdict(ent, ent.index);
+ ent.classname = "player";
+ InitClientResp(ent.client);
+ PutClientInServer(ent);
+ }
+
+ if (level.intermissiontime != 0) {
+ MoveClientToIntermission(ent);
+ }
+ else {
+ // send effect if in a multiplayer game
+ if (game.maxclients > 1) {
+ gi.WriteByte(svc_muzzleflash);
+ //gi.WriteShort(ent - g_edicts);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_LOGIN);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ gi.bprintf(PRINT_HIGH, ent.client.pers.netname + " entered the game\n");
+ }
+ }
+
+ // make sure all view stuff is valid
+ PlayerView.ClientEndServerFrame(ent);
+ }
+
+ /*
+ ===========
+ ClientUserInfoChanged
+
+ called whenever the player updates a userinfo variable.
+
+ The game can override any of the settings in place
+ (forcing skins or names, etc) before copying it off.
+ ============
+ */
+ public static String ClientUserinfoChanged(edict_t ent, String userinfo) {
+ String s;
+ int playernum;
+
+ // check for malformed or illegal info strings
+ if (!Info.Info_Validate(userinfo)) {
+ //strcpy(userinfo, "\\name\\badinfo\\skin\\male/grunt");
+ return "\\name\\badinfo\\skin\\male/grunt";
+ }
+
+ // set name
+ s = Info.Info_ValueForKey(userinfo, "name");
+
+ //strncpy(ent.client.pers.netname, s, sizeof(ent.client.pers.netname) - 1);
+ ent.client.pers.netname = s;
+
+ // set spectator
+ s = Info.Info_ValueForKey(userinfo, "spectator");
+ // spectators are only supported in deathmatch
+ if (deathmatch.value != 0 && !s.equals("0"))
+ ent.client.pers.spectator = true;
+ else
+ ent.client.pers.spectator = false;
+
+ // set skin
+ s = Info.Info_ValueForKey(userinfo, "skin");
+
+ playernum = ent.index - 1;
+
+ // combine name and skin into a configstring
+ gi.configstring(CS_PLAYERSKINS + playernum, ent.client.pers.netname + "\\" + s);
+
+ // fov
+ if (deathmatch.value != 0 && 0 != ((int) dmflags.value & DF_FIXED_FOV)) {
+ ent.client.ps.fov = 90;
+ }
+ else {
+ ent.client.ps.fov = atoi(Info.Info_ValueForKey(userinfo, "fov"));
+ if (ent.client.ps.fov < 1)
+ ent.client.ps.fov = 90;
+ else if (ent.client.ps.fov > 160)
+ ent.client.ps.fov = 160;
+ }
+
+ // handedness
+ s = Info.Info_ValueForKey(userinfo, "hand");
+ if (strlen(s) > 0) {
+ ent.client.pers.hand = atoi(s);
+ }
+
+ // save off the userinfo in case we want to check something later
+ //strncpy(ent.client.pers.userinfo, userinfo, sizeof(ent.client.pers.userinfo) - 1);
+ ent.client.pers.userinfo = userinfo;
+
+ return userinfo;
+ }
+
+ /*
+ ===========
+ ClientConnect
+
+ Called when a player begins connecting to the server.
+ The game can refuse entrance to a client by returning false.
+ If the client is allowed, the connection process will continue
+ and eventually get to ClientBegin()
+ Changing levels will NOT cause this to be called again, but
+ loadgames will.
+ ============
+ */
+ public static boolean ClientConnect(edict_t ent, String userinfo) {
+ String value;
+
+ // check to see if they are on the banned IP list
+ value = Info.Info_ValueForKey(userinfo, "ip");
+ if (GameSVCmds.SV_FilterPacket(value)) {
+ userinfo = Info.Info_SetValueForKey1(userinfo, "rejmsg", "Banned.");
+ return false;
+ }
+
+ // check for a spectator
+ value = Info.Info_ValueForKey(userinfo, "spectator");
+ if (deathmatch.value != 0 && value.length() != 0 && 0 != strcmp(value, "0")) {
+ int i, numspec;
+
+ if (!passwdOK(spectator_password.string, value)) {
+ userinfo = Info.Info_SetValueForKey1(userinfo, "rejmsg", "Spectator password required or incorrect.");
+ return false;
+ }
+
+ // count spectators
+ for (i = numspec = 0; i < maxclients.value; i++)
+ if (g_edicts[i + 1].inuse && g_edicts[i + 1].client.pers.spectator)
+ numspec++;
+
+ if (numspec >= maxspectators.value) {
+ userinfo = Info.Info_SetValueForKey1(userinfo, "rejmsg", "Server spectator limit is full.");
+ return false;
+ }
+ }
+ else {
+ // check for a password
+ value = Info.Info_ValueForKey(userinfo, "password");
+ if (!passwdOK(spectator_password.string, value)) {
+ userinfo = Info.Info_SetValueForKey1(userinfo, "rejmsg", "Password required or incorrect.");
+ return false;
+ }
+ }
+
+ // they can connect
+ ent.client = game.clients[ent.index - 1];
+
+ // if there is already a body waiting for us (a loadgame), just
+ // take it, otherwise spawn one from scratch
+ if (ent.inuse == false) {
+ // clear the respawning variables
+ InitClientResp(ent.client);
+ if (!game.autosaved || null == ent.client.pers.weapon)
+ InitClientPersistant(ent.client);
+ }
+
+ userinfo = ClientUserinfoChanged(ent, userinfo);
+
+ if (game.maxclients > 1)
+ gi.dprintf(ent.client.pers.netname + " connected\n");
+
+ ent.svflags = 0; // make sure we start with known default
+ ent.client.pers.connected = true;
+ return true;
+ }
+
+ /*
+ ===========
+ ClientDisconnect
+
+ Called when a player drops from the server.
+ Will not be called between levels.
+ ============
+ */
+ public static void ClientDisconnect(edict_t ent) {
+ int playernum;
+
+ if (ent.client == null)
+ return;
+
+ gi.bprintf(PRINT_HIGH, ent.client.pers.netname + " disconnected\n");
+
+ // send effect
+ gi.WriteByte(svc_muzzleflash);
+ gi.WriteShort(ent.index);
+ gi.WriteByte(MZ_LOGOUT);
+ gi.multicast(ent.s.origin, MULTICAST_PVS);
+
+ gi.unlinkentity(ent);
+ ent.s.modelindex = 0;
+ ent.solid = SOLID_NOT;
+ ent.inuse = false;
+ ent.classname = "disconnected";
+ ent.client.pers.connected = false;
+
+ playernum = ent.index - 1;
+ gi.configstring(CS_PLAYERSKINS + playernum, "");
+ }
+
+ //==============================================================
+
+ private static edict_t pm_passent;
+
+ // pmove doesn't need to know about passent and contentmask
+ public static pmove_t.TraceAdapter PM_trace = new pmove_t.TraceAdapter() {
+
+ public trace_t trace(float[] start, float[] mins, float[] maxs, float[] end) {
+ if (pm_passent.health > 0)
+ return gi.trace(start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID);
+ else
+ return gi.trace(start, mins, maxs, end, pm_passent, MASK_DEADSOLID);
+ }
+
+ };
+
+ /*
+ static int CheckBlock(, int c) {
+ int v, i;
+ v = 0;
+ for (i = 0; i < c; i++)
+ v += ((byte *) b)[i];
+ return v;
+ }
+
+ public static void PrintPmove(pmove_t * pm) {
+ unsigned c1, c2;
+
+ c1 = CheckBlock(& pm.s, sizeof(pm.s));
+ c2 = CheckBlock(& pm.cmd, sizeof(pm.cmd));
+ Com_Printf("sv %3i:%i %i\n", pm.cmd.impulse, c1, c2);
+ }
+ */
+
+ /*
+ ==============
+ ClientThink
+
+ This will be called once for each client frame, which will
+ usually be a couple times for each server frame.
+ ==============
+ */
+ public static void ClientThink(edict_t ent, usercmd_t ucmd) {
+ gclient_t client;
+ edict_t other;
+ int i, j;
+ pmove_t pm = null;
+
+ level.current_entity = ent;
+ client = ent.client;
+
+ if (level.intermissiontime != 0) {
+ client.ps.pmove.pm_type = PM_FREEZE;
+ // can exit intermission after five seconds
+ if (level.time > level.intermissiontime + 5.0f && 0 != (ucmd.buttons & BUTTON_ANY))
+ level.exitintermission = true;
+ return;
+ }
+
+ pm_passent = ent;
+
+ if (ent.client.chase_target != null) {
+
+ client.resp.cmd_angles[0] = SHORT2ANGLE(ucmd.angles[0]);
+ client.resp.cmd_angles[1] = SHORT2ANGLE(ucmd.angles[1]);
+ client.resp.cmd_angles[2] = SHORT2ANGLE(ucmd.angles[2]);
+
+ }
+ else {
+
+ // set up for pmove
+ //memset(& pm, 0, sizeof(pm));
+ pm = new pmove_t();
+
+ if (ent.movetype == MOVETYPE_NOCLIP)
+ client.ps.pmove.pm_type = PM_SPECTATOR;
+ else if (ent.s.modelindex != 255)
+ client.ps.pmove.pm_type = PM_GIB;
+ else if (ent.deadflag != 0)
+ client.ps.pmove.pm_type = PM_DEAD;
+ else
+ client.ps.pmove.pm_type = PM_NORMAL;
+
+ client.ps.pmove.gravity = (short) sv_gravity.value;
+ pm.s.set(client.ps.pmove);
+
+ for (i = 0; i < 3; i++) {
+ pm.s.origin[i] = (short) (ent.s.origin[i] * 8);
+ pm.s.velocity[i] = (short) (ent.velocity[i] * 8);
+ }
+
+ if (client.old_pmove.equals(pm.s)) {
+ pm.snapinitial = true;
+ // gi.dprintf ("pmove changed!\n");
+ }
+
+ // this should be a copy
+ pm.cmd.set(ucmd);
+
+ pm.trace = PM_trace; // adds default parms
+ pm.pointcontents = gi.pointcontents;
+
+ // perform a pmove
+ gi.Pmove(pm);
+
+ // save results of pmove
+ client.ps.pmove.set(pm.s);
+ client.old_pmove.set(pm.s);
+
+ for (i = 0; i < 3; i++) {
+ ent.s.origin[i] = pm.s.origin[i] * 0.125f;
+ ent.velocity[i] = pm.s.velocity[i] * 0.125f;
+ }
+
+ VectorCopy(pm.mins, ent.mins);
+ VectorCopy(pm.maxs, ent.maxs);
+
+ client.resp.cmd_angles[0] = SHORT2ANGLE(ucmd.angles[0]);
+ client.resp.cmd_angles[1] = SHORT2ANGLE(ucmd.angles[1]);
+ client.resp.cmd_angles[2] = SHORT2ANGLE(ucmd.angles[2]);
+
+ if (ent.groundentity != null && null == pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0)) {
+ gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
+ PlayerNoise(ent, ent.s.origin, PNOISE_SELF);
+ }
+
+ ent.viewheight = (int) pm.viewheight;
+ ent.waterlevel = (int) pm.waterlevel;
+ ent.watertype = pm.watertype;
+ ent.groundentity = pm.groundentity;
+ if (pm.groundentity != null)
+ ent.groundentity_linkcount = pm.groundentity.linkcount;
+
+ if (ent.deadflag != 0) {
+ client.ps.viewangles[ROLL] = 40;
+ client.ps.viewangles[PITCH] = -15;
+ client.ps.viewangles[YAW] = client.killer_yaw;
+ }
+ else {
+ VectorCopy(pm.viewangles, client.v_angle);
+ VectorCopy(pm.viewangles, client.ps.viewangles);
+ }
+
+ gi.linkentity(ent);
+
+ if (ent.movetype != MOVETYPE_NOCLIP)
+ G_TouchTriggers(ent);
+
+ // touch other objects
+ for (i = 0; i < pm.numtouch; i++) {
+ other = pm.touchents[i];
+ for (j = 0; j < i; j++)
+ if (pm.touchents[j] == other)
+ break;
+ if (j != i)
+ continue; // duplicated
+ if (other.touch == null)
+ continue;
+ other.touch.touch(other, ent, null, null);
+ }
+
+ }
+
+ client.oldbuttons = client.buttons;
+ client.buttons = ucmd.buttons;
+ client.latched_buttons |= client.buttons & ~client.oldbuttons;
+
+ // save light level the player is standing on for
+ // monster sighting AI
+ ent.light_level = ucmd.lightlevel;
+
+ // fire weapon from final position if needed
+ if ((client.latched_buttons & BUTTON_ATTACK) != 0) {
+ if (client.resp.spectator) {
+
+ client.latched_buttons = 0;
+
+ if (client.chase_target != null) {
+ client.chase_target = null;
+ client.ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
+ }
+ else
+ GetChaseTarget(ent);
+
+ }
+ else if (!client.weapon_thunk) {
+ client.weapon_thunk = true;
+ Think_Weapon(ent);
+ }
+ }
+
+ if (client.resp.spectator) {
+ if (ucmd.upmove >= 10) {
+ if (0 == (client.ps.pmove.pm_flags & PMF_JUMP_HELD)) {
+ client.ps.pmove.pm_flags |= PMF_JUMP_HELD;
+ if (client.chase_target != null)
+ ChaseNext(ent);
+ else
+ GetChaseTarget(ent);
+ }
+ }
+ else
+ client.ps.pmove.pm_flags &= ~PMF_JUMP_HELD;
+ }
+
+ // update chase cam if being followed
+ for (i = 1; i <= maxclients.value; i++) {
+ other = g_edicts[i];
+ if (other.inuse && other.client.chase_target == ent)
+ UpdateChaseCam(other);
+ }
+ }
+
+ /*
+ ==============
+ ClientBeginServerFrame
+
+ This will be called once for each server frame, before running
+ any other entities in the world.
+ ==============
+ */
+ public static void ClientBeginServerFrame(edict_t ent) {
+ gclient_t client;
+ int buttonMask;
+
+ if (level.intermissiontime != 0)
+ return;
+
+ client = ent.client;
+
+ if (deathmatch.value != 0
+ && client.pers.spectator != client.resp.spectator
+ && (level.time - client.respawn_time) >= 5) {
+ spectator_respawn(ent);
+ return;
+ }
+
+ // run weapon animations if it hasn't been done by a ucmd_t
+ if (!client.weapon_thunk && !client.resp.spectator)
+ Think_Weapon(ent);
+ else
+ client.weapon_thunk = false;
+
+ if (ent.deadflag != 0) {
+ // wait for any button just going down
+ if (level.time > client.respawn_time) {
+ // in deathmatch, only wait for attack button
+ if (deathmatch.value != 0)
+ buttonMask = BUTTON_ATTACK;
+ else
+ buttonMask = -1;
+
+ if ((client.latched_buttons & buttonMask) != 0
+ || (deathmatch.value != 0 && 0 != ((int) dmflags.value & DF_FORCE_RESPAWN))) {
+ respawn(ent);
+ client.latched_buttons = 0;
+ }
+ }
+ return;
+ }
+
+ // add player trail so monsters can follow
+ if (deathmatch.value != 0)
+ if (!visible(ent, PlayerTrail.LastSpot()))
+ PlayerTrail.Add(ent.s.old_origin);
+
+ client.latched_buttons = 0;
+ }
+}
diff --git a/src/jake2/game/PlayerHud.java b/src/jake2/game/PlayerHud.java
new file mode 100644
index 0000000..ff02e75
--- /dev/null
+++ b/src/jake2/game/PlayerHud.java
@@ -0,0 +1,573 @@
+/*
+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: PlayerHud.java,v 1.1 2004-07-07 19:59:23 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+import jake2.util.Vargs;
+
+public class PlayerHud extends GameTarget {
+
+ /*
+ ======================================================================
+
+ INTERMISSION
+
+ ======================================================================
+ */
+
+ public static void MoveClientToIntermission(edict_t ent) {
+ if (deathmatch.value != 0 || coop.value != 0)
+ ent.client.showscores = true;
+ VectorCopy(level.intermission_origin, ent.s.origin);
+ ent.client.ps.pmove.origin[0] = (short) (level.intermission_origin[0] * 8);
+ ent.client.ps.pmove.origin[1] = (short) (level.intermission_origin[1] * 8);
+ ent.client.ps.pmove.origin[2] = (short) (level.intermission_origin[2] * 8);
+ VectorCopy(level.intermission_angle, ent.client.ps.viewangles);
+ ent.client.ps.pmove.pm_type = PM_FREEZE;
+ ent.client.ps.gunindex = 0;
+ ent.client.ps.blend[3] = 0;
+ ent.client.ps.rdflags &= ~RDF_UNDERWATER;
+
+ // clean up powerup info
+ ent.client.quad_framenum = 0;
+ ent.client.invincible_framenum = 0;
+ ent.client.breather_framenum = 0;
+ ent.client.enviro_framenum = 0;
+ ent.client.grenade_blew_up = false;
+ ent.client.grenade_time = 0;
+
+ ent.viewheight = 0;
+ ent.s.modelindex = 0;
+ ent.s.modelindex2 = 0;
+ ent.s.modelindex3 = 0;
+ ent.s.modelindex = 0;
+ ent.s.effects = 0;
+ ent.s.sound = 0;
+ ent.solid = SOLID_NOT;
+
+ // add the layout
+
+ if (deathmatch.value != 0 || coop.value != 0) {
+ DeathmatchScoreboardMessage(ent, null);
+ gi.unicast(ent, true);
+ }
+
+ }
+
+ public static void BeginIntermission(edict_t targ) {
+ int i, n;
+ edict_t ent, client;
+
+ if (level.intermissiontime != 0)
+ return; // already activated
+
+ game.autosaved = false;
+
+ // respawn any dead clients
+ for (i = 0; i < maxclients.value; i++) {
+ client = g_edicts[1 + i];
+ if (!client.inuse)
+ continue;
+ if (client.health <= 0)
+ PlayerClient.respawn(client);
+ }
+
+ level.intermissiontime = level.time;
+ level.changemap = targ.map;
+
+ if (level.changemap.indexOf('*') > -1) {
+ if (coop.value != 0) {
+ for (i = 0; i < maxclients.value; i++) {
+ client = g_edicts[1 + i];
+ if (!client.inuse)
+ continue;
+ // strip players of all keys between units
+ for (n = 0; n < MAX_ITEMS; n++) {
+ if ((itemlist[n].flags & IT_KEY) != 0)
+ client.client.pers.inventory[n] = 0;
+ }
+ }
+ }
+ }
+ else {
+ if (0 == deathmatch.value) {
+ level.exitintermission = true; // go immediately to the next level
+ return;
+ }
+ }
+
+ level.exitintermission = false;
+
+ // find an intermission spot
+ ent = G_FindEdict(null, findByClass, "info_player_intermission");
+ if (ent == null) { // the map creator forgot to put in an intermission point...
+ ent = G_FindEdict(null, findByClass, "info_player_start");
+ if (ent == null)
+ ent = G_FindEdict(null, findByClass, "info_player_deathmatch");
+ }
+ else { // chose one of four spots
+ i = rand() & 3;
+ EdictIterator es = null;
+
+ while (i-- > 0) {
+ es = G_Find(es, findByClass, "info_player_intermission");
+
+ if (es == null) // wrap around the list
+ continue;
+ ent = es.o;
+
+ }
+ }
+
+ VectorCopy(ent.s.origin, level.intermission_origin);
+ VectorCopy(ent.s.angles, level.intermission_angle);
+
+ // move all clients to the intermission point
+ for (i = 0; i < maxclients.value; i++) {
+ client = g_edicts[1 + i];
+ if (!client.inuse)
+ continue;
+ MoveClientToIntermission(client);
+ }
+ }
+
+ /*
+ ==================
+ DeathmatchScoreboardMessage
+
+ ==================
+ */
+ public static void DeathmatchScoreboardMessage(edict_t ent, edict_t killer) {
+ StringBuffer string = new StringBuffer(1400);
+ //String string;
+ //char entry[1024];
+ //char string[1400];
+ int stringlength;
+ int i, j, k;
+ int sorted[] = new int[MAX_CLIENTS];
+ int sortedscores[] = new int[MAX_CLIENTS];
+ int score, total;
+ int picnum;
+ int x, y;
+ gclient_t cl;
+ edict_t cl_ent;
+ String tag;
+
+ // sort the clients by score
+ total = 0;
+ for (i = 0; i < game.maxclients; i++) {
+ cl_ent = g_edicts[1 + i];
+ if (!cl_ent.inuse || game.clients[i].resp.spectator)
+ continue;
+ score = game.clients[i].resp.score;
+ for (j = 0; j < total; j++) {
+ if (score > sortedscores[j])
+ break;
+ }
+ for (k = total; k > j; k--) {
+ sorted[k] = sorted[k - 1];
+ sortedscores[k] = sortedscores[k - 1];
+ }
+ sorted[j] = i;
+ sortedscores[j] = score;
+ total++;
+ }
+
+ // print level name and exit rules
+ //string[0] = 0;
+ //stringlength = strlen(string);
+
+ // add the clients in sorted order
+ if (total > 12)
+ total = 12;
+
+ for (i = 0; i < total; i++) {
+ cl = game.clients[sorted[i]];
+ cl_ent = g_edicts[1 + sorted[i]];
+
+ picnum = gi.imageindex("i_fixme");
+ x = (i >= 6) ? 160 : 0;
+ y = 32 + 32 * (i % 6);
+
+ // add a dogtag
+ if (cl_ent == ent)
+ tag = "tag1";
+ else if (cl_ent == killer)
+ tag = "tag2";
+ else
+ tag = null;
+
+ if (tag != null) {
+ string.append("xv ").append(x + 32).append(" yv ").append(y).append(" picn ").append(tag);
+ /*
+ //Com_sprintf(entry, sizeof(entry), "xv %i yv %i picn %s ", x + 32, y, tag);
+ j = strlen(entry);
+ if (stringlength + j > 1024)
+ break;
+ strcpy(string + stringlength, entry);
+ stringlength += j;
+ */
+ }
+
+ // send the layout
+ string
+ .append("client ")
+ .append(x)
+ .append(" ")
+ .append(y)
+ .append(" ")
+ .append(sorted[i])
+ .append(" ")
+ .append(cl.resp.score)
+ .append(" ")
+ .append(cl.ping)
+ .append(" ")
+ .append((level.framenum - cl.resp.enterframe) / 600);
+
+ /*
+ Com_sprintf(
+ entry,
+ sizeof(entry),
+ "client %i %i %i %i %i %i ",
+ x,
+ y,
+ sorted[i],
+ cl.resp.score,
+ cl.ping,
+ (level.framenum - cl.resp.enterframe) / 600);
+ j = strlen(entry);
+ if (stringlength + j > 1024)
+ break;
+ strcpy(string + stringlength, entry);
+ stringlength += j;
+ */
+
+ }
+
+ gi.WriteByte(svc_layout);
+ gi.WriteString(string.toString());
+ }
+
+ /*
+ ==================
+ DeathmatchScoreboard
+
+ Draw instead of help message.
+ Note that it isn't that hard to overflow the 1400 byte message limit!
+ ==================
+ */
+ public static void DeathmatchScoreboard(edict_t ent) {
+ DeathmatchScoreboardMessage(ent, ent.enemy);
+ gi.unicast(ent, true);
+ }
+
+ /*
+ ==================
+ Cmd_Score_f
+
+ Display the scoreboard
+ ==================
+ */
+ public static void Cmd_Score_f(edict_t ent) {
+ ent.client.showinventory = false;
+ ent.client.showhelp = false;
+
+ if (0 == deathmatch.value && 0 == coop.value)
+ return;
+
+ if (ent.client.showscores) {
+ ent.client.showscores = false;
+ return;
+ }
+
+ ent.client.showscores = true;
+ DeathmatchScoreboard(ent);
+ }
+
+ /*
+ ==================
+ HelpComputer
+
+ Draw help computer.
+ ==================
+ */
+ public static void HelpComputer(edict_t ent) {
+ //char string[1024];
+ String string;
+
+ String sk;
+
+ if (skill.value == 0)
+ sk = "easy";
+ else if (skill.value == 1)
+ sk = "medium";
+ else if (skill.value == 2)
+ sk = "hard";
+ else
+ sk = "hard+";
+
+ // send the layout
+
+ string = Com.sprintf("xv 32 yv 8 picn help " + // background
+ "xv 202 yv 12 string2 \"%s\" " + // skill
+ "xv 0 yv 24 cstring2 \"%s\" " + // level name
+ "xv 0 yv 54 cstring2 \"%s\" " + // help 1
+ "xv 0 yv 110 cstring2 \"%s\" " + // help 2
+ "xv 50 yv 164 string2 \" kills goals secrets\" " + "xv 50 yv 172 string2 \"%3i/%3i %i/%i %i/%i\" ",
+ new Vargs()
+ .add(sk)
+ .add(level.level_name)
+ .add(game.helpmessage1)
+ .add(game.helpmessage2)
+ .add(level.killed_monsters)
+ .add(level.total_monsters)
+ .add(level.found_goals)
+ .add(level.total_goals)
+ .add(level.found_secrets)
+ .add(level.total_secrets));
+
+ gi.WriteByte(svc_layout);
+ gi.WriteString(string);
+ gi.unicast(ent, true);
+ }
+
+ /*
+ ==================
+ Cmd_Help_f
+
+ Display the current help message
+ ==================
+ */
+ public static void Cmd_Help_f(edict_t ent) {
+ // this is for backwards compatability
+ if (deathmatch.value != 0) {
+ Cmd_Score_f(ent);
+ return;
+ }
+
+ ent.client.showinventory = false;
+ ent.client.showscores = false;
+
+ if (ent.client.showhelp && (ent.client.pers.game_helpchanged == game.helpchanged)) {
+ ent.client.showhelp = false;
+ return;
+ }
+
+ ent.client.showhelp = true;
+ ent.client.pers.helpchanged = 0;
+ HelpComputer(ent);
+ }
+
+ //=======================================================================
+
+ /*
+ ===============
+ G_SetStats
+ ===============
+ */
+ public static void G_SetStats(edict_t ent) {
+ gitem_t item;
+ int index, cells = 0;
+ int power_armor_type;
+
+ //
+ // health
+ //
+ ent.client.ps.stats[STAT_HEALTH_ICON] = (short) level.pic_health;
+ ent.client.ps.stats[STAT_HEALTH] = (short) ent.health;
+
+ //
+ // ammo
+ //
+ if (0 == ent.client.ammo_index /* || !ent.client.pers.inventory[ent.client.ammo_index] */
+ ) {
+ ent.client.ps.stats[STAT_AMMO_ICON] = 0;
+ ent.client.ps.stats[STAT_AMMO] = 0;
+ }
+ else {
+ item = itemlist[ent.client.ammo_index];
+ ent.client.ps.stats[STAT_AMMO_ICON] = (short) gi.imageindex(item.icon);
+ ent.client.ps.stats[STAT_AMMO] = (short) ent.client.pers.inventory[ent.client.ammo_index];
+ }
+
+ //
+ // armor
+ //
+ power_armor_type = PowerArmorType(ent);
+ if (power_armor_type != 0) {
+ cells = ent.client.pers.inventory[ITEM_INDEX(FindItem("cells"))];
+ if (cells == 0) { // ran out of cells for power armor
+ ent.flags &= ~FL_POWER_ARMOR;
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
+ power_armor_type = 0;
+ ;
+ }
+ }
+
+ index = ArmorIndex(ent);
+ if (power_armor_type != 0 && (0 == index || 0 != (level.framenum & 8))) { // flash between power armor and other armor icon
+ ent.client.ps.stats[STAT_ARMOR_ICON] = (short) gi.imageindex("i_powershield");
+ ent.client.ps.stats[STAT_ARMOR] = (short) cells;
+ }
+ else if (index != 0) {
+ item = GetItemByIndex(index);
+ ent.client.ps.stats[STAT_ARMOR_ICON] = (short) gi.imageindex(item.icon);
+ ent.client.ps.stats[STAT_ARMOR] = (short) ent.client.pers.inventory[index];
+ }
+ else {
+ ent.client.ps.stats[STAT_ARMOR_ICON] = 0;
+ ent.client.ps.stats[STAT_ARMOR] = 0;
+ }
+
+ //
+ // pickup message
+ //
+ if (level.time > ent.client.pickup_msg_time) {
+ ent.client.ps.stats[STAT_PICKUP_ICON] = 0;
+ ent.client.ps.stats[STAT_PICKUP_STRING] = 0;
+ }
+
+ //
+ // timers
+ //
+ if (ent.client.quad_framenum > level.framenum) {
+ ent.client.ps.stats[STAT_TIMER_ICON] = (short) gi.imageindex("p_quad");
+ ent.client.ps.stats[STAT_TIMER] = (short) ((ent.client.quad_framenum - level.framenum) / 10);
+ }
+ else if (ent.client.invincible_framenum > level.framenum) {
+ ent.client.ps.stats[STAT_TIMER_ICON] = (short) gi.imageindex("p_invulnerability");
+ ent.client.ps.stats[STAT_TIMER] = (short) ((ent.client.invincible_framenum - level.framenum) / 10);
+ }
+ else if (ent.client.enviro_framenum > level.framenum) {
+ ent.client.ps.stats[STAT_TIMER_ICON] = (short) gi.imageindex("p_envirosuit");
+ ent.client.ps.stats[STAT_TIMER] = (short) ((ent.client.enviro_framenum - level.framenum) / 10);
+ }
+ else if (ent.client.breather_framenum > level.framenum) {
+ ent.client.ps.stats[STAT_TIMER_ICON] = (short) gi.imageindex("p_rebreather");
+ ent.client.ps.stats[STAT_TIMER] = (short) ((ent.client.breather_framenum - level.framenum) / 10);
+ }
+ else {
+ ent.client.ps.stats[STAT_TIMER_ICON] = 0;
+ ent.client.ps.stats[STAT_TIMER] = 0;
+ }
+
+ //
+ // selected item
+ //
+ // bugfix rst
+ if (ent.client.pers.selected_item <= 0)
+ ent.client.ps.stats[STAT_SELECTED_ICON] = 0;
+ else
+ ent.client.ps.stats[STAT_SELECTED_ICON] = (short) gi.imageindex(itemlist[ent.client.pers.selected_item].icon);
+
+ ent.client.ps.stats[STAT_SELECTED_ITEM] = (short) ent.client.pers.selected_item;
+
+ //
+ // layouts
+ //
+ ent.client.ps.stats[STAT_LAYOUTS] = 0;
+
+ if (deathmatch.value != 0) {
+ if (ent.client.pers.health <= 0 || level.intermissiontime != 0 || ent.client.showscores)
+ ent.client.ps.stats[STAT_LAYOUTS] |= 1;
+ if (ent.client.showinventory && ent.client.pers.health > 0)
+ ent.client.ps.stats[STAT_LAYOUTS] |= 2;
+ }
+ else {
+ if (ent.client.showscores || ent.client.showhelp)
+ ent.client.ps.stats[STAT_LAYOUTS] |= 1;
+ if (ent.client.showinventory && ent.client.pers.health > 0)
+ ent.client.ps.stats[STAT_LAYOUTS] |= 2;
+ }
+
+ //
+ // frags
+ //
+ ent.client.ps.stats[STAT_FRAGS] = (short) ent.client.resp.score;
+
+ //
+ // help icon / current weapon if not shown
+ //
+ if (ent.client.pers.helpchanged != 0 && (level.framenum & 8) != 0)
+ ent.client.ps.stats[STAT_HELPICON] = (short) gi.imageindex("i_help");
+ else if ((ent.client.pers.hand == CENTER_HANDED || ent.client.ps.fov > 91) && ent.client.pers.weapon != null)
+ ent.client.ps.stats[STAT_HELPICON] = (short) gi.imageindex(ent.client.pers.weapon.icon);
+ else
+ ent.client.ps.stats[STAT_HELPICON] = 0;
+
+ ent.client.ps.stats[STAT_SPECTATOR] = 0;
+ }
+
+ /*
+ ===============
+ G_CheckChaseStats
+ ===============
+ */
+ public static void G_CheckChaseStats(edict_t ent) {
+ int i;
+ gclient_t cl;
+
+ for (i = 1; i <= maxclients.value; i++) {
+ cl = g_edicts[i].client;
+ if (!g_edicts[i].inuse || cl.chase_target != ent)
+ continue;
+ //memcpy(cl.ps.stats, ent.client.ps.stats, sizeof(cl.ps.stats));
+ System.arraycopy(ent.client.ps.stats, 0, cl.ps.stats, 0, Defines.MAX_STATS);
+
+ G_SetSpectatorStats(g_edicts[i]);
+ }
+ }
+
+ /*
+ ===============
+ G_SetSpectatorStats
+ ===============
+ */
+ public static void G_SetSpectatorStats(edict_t ent) {
+ gclient_t cl = ent.client;
+
+ if (null == cl.chase_target)
+ G_SetStats(ent);
+
+ cl.ps.stats[STAT_SPECTATOR] = 1;
+
+ // layouts are independant in spectator
+ cl.ps.stats[STAT_LAYOUTS] = 0;
+ if (cl.pers.health <= 0 || level.intermissiontime != 0 || cl.showscores)
+ cl.ps.stats[STAT_LAYOUTS] |= 1;
+ if (cl.showinventory && cl.pers.health > 0)
+ cl.ps.stats[STAT_LAYOUTS] |= 2;
+
+ if (cl.chase_target != null && cl.chase_target.inuse)
+ //cl.ps.stats[STAT_CHASE] = (short) (CS_PLAYERSKINS + (cl.chase_target - g_edicts) - 1);
+ cl.ps.stats[STAT_CHASE] = (short) (CS_PLAYERSKINS + cl.chase_target.index - 1);
+ else
+ cl.ps.stats[STAT_CHASE] = 0;
+ }
+
+}
diff --git a/src/jake2/game/PlayerTrail.java b/src/jake2/game/PlayerTrail.java
new file mode 100644
index 0000000..09af3d8
--- /dev/null
+++ b/src/jake2/game/PlayerTrail.java
@@ -0,0 +1,151 @@
+/*
+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 13.11.2003 by RST.
+// $Id: PlayerTrail.java,v 1.1 2004-07-07 19:59:23 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+import jake2.util.*;
+
+public class PlayerTrail extends PlayerHud {
+
+ /*
+ ==============================================================================
+
+ PLAYER TRAIL
+
+ ==============================================================================
+
+ This is a circular list containing the a list of points of where
+ the player has been recently. It is used by monsters for pursuit.
+
+ .origin the spot
+ .owner forward link
+ .aiment backward link
+ */
+
+ static int TRAIL_LENGTH= 8;
+
+ static edict_t trail[]= new edict_t[TRAIL_LENGTH];
+ static {
+ //TODO: potential error
+ for (int n=0; n < TRAIL_LENGTH; n++)
+ trail[n] = new edict_t(n);
+ }
+ static int trail_head;
+ static boolean trail_active= false;
+
+ static int NEXT(int n) {
+ return (n + 1) % TRAIL_LENGTH;
+ }
+
+ static int PREV(int n) {
+ return (n + TRAIL_LENGTH - 1) % TRAIL_LENGTH;
+ }
+
+ static void Init() {
+
+ // FIXME || coop
+ if (deathmatch.value != 0)
+ return;
+
+ for (int n= 0; n < TRAIL_LENGTH; n++) {
+ trail[n]= G_Spawn();
+ trail[n].classname= "player_trail";
+ }
+
+ trail_head= 0;
+ trail_active= true;
+ }
+
+ static void Add(float[] spot) {
+ float[] temp= { 0, 0, 0 };
+
+ if (!trail_active)
+ return;
+
+ Math3D.VectorCopy(spot, trail[trail_head].s.origin);
+
+ trail[trail_head].timestamp= level.time;
+
+ Math3D.VectorSubtract(spot, trail[PREV(trail_head)].s.origin, temp);
+ trail[trail_head].s.angles[1]= Math3D.vectoyaw(temp);
+
+ trail_head= NEXT(trail_head);
+ }
+
+ static void New(float[] spot) {
+ if (!trail_active)
+ return;
+
+ Init();
+ Add(spot);
+ }
+
+ static edict_t PickFirst(edict_t self) {
+
+ if (!trail_active)
+ return null;
+
+ int marker= trail_head;
+
+ for (int n= TRAIL_LENGTH; n > 0; n--) {
+ if (trail[marker].timestamp <= self.monsterinfo.trail_time)
+ marker= NEXT(marker);
+ else
+ break;
+ }
+
+ if (visible(self, trail[marker])) {
+ return trail[marker];
+ }
+
+ if (visible(self, trail[PREV(marker)])) {
+ return trail[PREV(marker)];
+ }
+
+ return trail[marker];
+ }
+
+ static edict_t PickNext(edict_t self) {
+ int marker;
+ int n;
+
+ if (!trail_active)
+ return null;
+
+ for (marker= trail_head, n= TRAIL_LENGTH; n > 0; n--) {
+ if (trail[marker].timestamp <= self.monsterinfo.trail_time)
+ marker= NEXT(marker);
+ else
+ break;
+ }
+
+ return trail[marker];
+ }
+
+ static edict_t LastSpot() {
+ return trail[PREV(trail_head)];
+ }
+
+
+}
diff --git a/src/jake2/game/PlayerView.java b/src/jake2/game/PlayerView.java
new file mode 100644
index 0000000..289aa0f
--- /dev/null
+++ b/src/jake2/game/PlayerView.java
@@ -0,0 +1,1054 @@
+/*
+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: PlayerView.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class PlayerView extends PlayerClient {
+
+ public static edict_t current_player;
+ public static gclient_t current_client;
+
+ public static float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
+ public static float xyspeed;
+
+ public static float bobmove;
+ public static int bobcycle; // odd cycles are right foot going forward
+ public static float bobfracsin; // sin(bobfrac*M_PI)
+
+ /*
+ ===============
+ SV_CalcRoll
+
+ ===============
+ */
+ public static float SV_CalcRoll(float[] angles, float[] velocity) {
+ float sign;
+ float side;
+ float value;
+
+ side = DotProduct(velocity, right);
+ sign = side < 0 ? -1 : 1;
+ side = Math.abs(side);
+
+ value = sv_rollangle.value;
+
+ if (side < sv_rollspeed.value)
+ side = side * value / sv_rollspeed.value;
+ else
+ side = value;
+
+ return side * sign;
+ }
+
+ /*
+ ===============
+ P_DamageFeedback
+
+ Handles color blends and view kicks
+ ===============
+ */
+ private static int xxxi = 0;
+
+ public static void P_DamageFeedback(edict_t player) {
+ gclient_t client;
+ float side;
+ float realcount, count, kick;
+ float[] v = { 0, 0, 0 };
+ int r, l;
+ float[] power_color = { 0.0f, 1.0f, 0.0f };
+ float[] acolor = { 1.0f, 1.0f, 1.0f };
+ float[] bcolor = { 1.0f, 0.0f, 0.0f };
+
+ client = player.client;
+
+ // flash the backgrounds behind the status numbers
+ client.ps.stats[STAT_FLASHES] = 0;
+ if (client.damage_blood != 0)
+ client.ps.stats[STAT_FLASHES] |= 1;
+ if (client.damage_armor != 0 && 0 == (player.flags & FL_GODMODE) && (client.invincible_framenum <= level.framenum))
+ client.ps.stats[STAT_FLASHES] |= 2;
+
+ // total points of damage shot at the player this frame
+ count = (client.damage_blood + client.damage_armor + client.damage_parmor);
+
+ if (count == 0)
+ return; // didn't take any damage
+
+ // start a pain animation if still in the player model
+ if ((client.anim_priority < ANIM_PAIN) & (player.s.modelindex == 255)) {
+ client.anim_priority = ANIM_PAIN;
+ if ((client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
+ player.s.frame = FRAME_crpain1 - 1;
+ client.anim_end = FRAME_crpain4;
+ }
+ else {
+
+ xxxi = (xxxi + 1) % 3;
+ switch (xxxi) {
+ case 0 :
+ player.s.frame = FRAME_pain101 - 1;
+ client.anim_end = FRAME_pain104;
+ break;
+ case 1 :
+ player.s.frame = FRAME_pain201 - 1;
+ client.anim_end = FRAME_pain204;
+ break;
+ case 2 :
+ player.s.frame = FRAME_pain301 - 1;
+ client.anim_end = FRAME_pain304;
+ break;
+ }
+ }
+ }
+
+ realcount = count;
+ if (count < 10)
+ count = 10; // always make a visible effect
+
+ // play an apropriate pain sound
+ if ((level.time > player.pain_debounce_time)
+ && 0 == (player.flags & FL_GODMODE)
+ && (client.invincible_framenum <= level.framenum)) {
+ r = 1 + (rand() & 1);
+ player.pain_debounce_time = level.time + 0.7f;
+ if (player.health < 25)
+ l = 25;
+ else if (player.health < 50)
+ l = 50;
+ else if (player.health < 75)
+ l = 75;
+ else
+ l = 100;
+ gi.sound(player, CHAN_VOICE, gi.soundindex("*pain" + l + "_" + r + ".wav"), 1, ATTN_NORM, 0);
+ }
+
+ // the total alpha of the blend is always proportional to count
+ if (client.damage_alpha < 0)
+ client.damage_alpha = 0;
+ client.damage_alpha += count * 0.01f;
+ if (client.damage_alpha < 0.2f)
+ client.damage_alpha = 0.2f;
+ if (client.damage_alpha > 0.6f)
+ client.damage_alpha = 0.6f; // don't go too saturated
+
+ // the color of the blend will vary based on how much was absorbed
+ // by different armors
+ VectorClear(v);
+ if (client.damage_parmor != 0)
+ VectorMA(v, (float) client.damage_parmor / realcount, power_color, v);
+
+ if (client.damage_armor != 0)
+ VectorMA(v, (float) client.damage_armor / realcount, acolor, v);
+
+ if (client.damage_blood != 0)
+ VectorMA(v, (float) client.damage_blood / realcount, bcolor, v);
+ VectorCopy(v, client.damage_blend);
+
+ //
+ // calculate view angle kicks
+ //
+ kick = Math.abs(client.damage_knockback);
+ if (kick != 0 && player.health > 0) // kick of 0 means no view adjust at all
+ {
+ kick = kick * 100 / player.health;
+
+ if (kick < count * 0.5)
+ kick = count * 0.5f;
+ if (kick > 50)
+ kick = 50;
+
+ VectorSubtract(client.damage_from, player.s.origin, v);
+ VectorNormalize(v);
+
+ side = DotProduct(v, right);
+ client.v_dmg_roll = kick * side * 0.3f;
+
+ side = -DotProduct(v, forward);
+ client.v_dmg_pitch = kick * side * 0.3f;
+
+ client.v_dmg_time = level.time + DAMAGE_TIME;
+ }
+
+ //
+ // clear totals
+ //
+ client.damage_blood = 0;
+ client.damage_armor = 0;
+ client.damage_parmor = 0;
+ client.damage_knockback = 0;
+ }
+
+ /*
+ ===============
+ SV_CalcViewOffset
+
+ Auto pitching on slopes?
+
+ fall from 128: 400 = 160000
+ fall from 256: 580 = 336400
+ fall from 384: 720 = 518400
+ fall from 512: 800 = 640000
+ fall from 640: 960 =
+
+ damage = deltavelocity*deltavelocity * 0.0001
+
+ ===============
+ */
+ public static void SV_CalcViewOffset(edict_t ent) {
+ float angles[] = { 0, 0, 0 };
+ float bob;
+ float ratio;
+ float delta;
+ float[] v = { 0, 0, 0 };
+
+ //===================================
+
+ // base angles
+ angles = ent.client.ps.kick_angles;
+
+ // if dead, fix the angle and don't add any kick
+ if (ent.deadflag != 0) {
+ VectorClear(angles);
+
+ ent.client.ps.viewangles[ROLL] = 40;
+ ent.client.ps.viewangles[PITCH] = -15;
+ ent.client.ps.viewangles[YAW] = ent.client.killer_yaw;
+ }
+ else {
+ // add angles based on weapon kick
+
+ VectorCopy(ent.client.kick_angles, angles);
+
+ // add angles based on damage kick
+
+ ratio = (ent.client.v_dmg_time - level.time) / DAMAGE_TIME;
+ if (ratio < 0) {
+ ratio = 0;
+ ent.client.v_dmg_pitch = 0;
+ ent.client.v_dmg_roll = 0;
+ }
+ angles[PITCH] += ratio * ent.client.v_dmg_pitch;
+ angles[ROLL] += ratio * ent.client.v_dmg_roll;
+
+ // add pitch based on fall kick
+
+ ratio = (ent.client.fall_time - level.time) / FALL_TIME;
+ if (ratio < 0)
+ ratio = 0;
+ angles[PITCH] += ratio * ent.client.fall_value;
+
+ // add angles based on velocity
+
+ delta = DotProduct(ent.velocity, forward);
+ angles[PITCH] += delta * run_pitch.value;
+
+ delta = DotProduct(ent.velocity, right);
+ angles[ROLL] += delta * run_roll.value;
+
+ // add angles based on bob
+
+ delta = bobfracsin * bob_pitch.value * xyspeed;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0)
+ delta *= 6; // crouching
+ angles[PITCH] += delta;
+ delta = bobfracsin * bob_roll.value * xyspeed;
+ if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0)
+ delta *= 6; // crouching
+ if ((bobcycle & 1) != 0)
+ delta = -delta;
+ angles[ROLL] += delta;
+ }
+
+ //===================================
+
+ // base origin
+
+ VectorClear(v);
+
+ // add view height
+
+ v[2] += ent.viewheight;
+
+ // add fall height
+
+ ratio = (ent.client.fall_time - level.time) / FALL_TIME;
+ if (ratio < 0)
+ ratio = 0;
+ v[2] -= ratio * ent.client.fall_value * 0.4;
+
+ // add bob height
+
+ bob = bobfracsin * xyspeed * bob_up.value;
+ if (bob > 6)
+ bob = 6;
+ //gi.DebugGraph (bob *2, 255);
+ v[2] += bob;
+
+ // add kick offset
+
+ VectorAdd(v, ent.client.kick_origin, v);
+
+ // absolutely bound offsets
+ // so the view can never be outside the player box
+
+ if (v[0] < -14)
+ v[0] = -14;
+ else if (v[0] > 14)
+ v[0] = 14;
+ if (v[1] < -14)
+ v[1] = -14;
+ else if (v[1] > 14)
+ v[1] = 14;
+ if (v[2] < -22)
+ v[2] = -22;
+ else if (v[2] > 30)
+ v[2] = 30;
+
+ VectorCopy(v, ent.client.ps.viewoffset);
+ }
+
+ /*
+ ==============
+ SV_CalcGunOffset
+ ==============
+ */
+ public static void SV_CalcGunOffset(edict_t ent) {
+ int i;
+ float delta;
+
+ // gun angles from bobbing
+ ent.client.ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005f;
+ ent.client.ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01f;
+ if ((bobcycle & 1) != 0) {
+ ent.client.ps.gunangles[ROLL] = -ent.client.ps.gunangles[ROLL];
+ ent.client.ps.gunangles[YAW] = -ent.client.ps.gunangles[YAW];
+ }
+
+ ent.client.ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005f;
+
+ // gun angles from delta movement
+ for (i = 0; i < 3; i++) {
+ delta = ent.client.oldviewangles[i] - ent.client.ps.viewangles[i];
+ if (delta > 180)
+ delta -= 360;
+ if (delta < -180)
+ delta += 360;
+ if (delta > 45)
+ delta = 45;
+ if (delta < -45)
+ delta = -45;
+ if (i == YAW)
+ ent.client.ps.gunangles[ROLL] += 0.1 * delta;
+ ent.client.ps.gunangles[i] += 0.2 * delta;
+ }
+
+ // gun height
+ VectorClear(ent.client.ps.gunoffset);
+ // ent.ps.gunorigin[2] += bob;
+
+ // gun_x / gun_y / gun_z are development tools
+ for (i = 0; i < 3; i++) {
+ ent.client.ps.gunoffset[i] += forward[i] * (gun_y.value);
+ ent.client.ps.gunoffset[i] += right[i] * gun_x.value;
+ ent.client.ps.gunoffset[i] += up[i] * (-gun_z.value);
+ }
+ }
+
+ /*
+ =============
+ SV_AddBlend
+ =============
+ */
+ public static void SV_AddBlend(float r, float g, float b, float a, float v_blend[]) {
+ float a2, a3;
+
+ if (a <= 0)
+ return;
+ a2 = v_blend[3] + (1 - v_blend[3]) * a; // new total alpha
+ a3 = v_blend[3] / a2; // fraction of color from old
+
+ v_blend[0] = v_blend[0] * a3 + r * (1 - a3);
+ v_blend[1] = v_blend[1] * a3 + g * (1 - a3);
+ v_blend[2] = v_blend[2] * a3 + b * (1 - a3);
+ v_blend[3] = a2;
+ }
+
+ /*
+ =============
+ SV_CalcBlend
+ =============
+ */
+ public static void SV_CalcBlend(edict_t ent) {
+ int contents;
+ float[] vieworg = { 0, 0, 0 };
+ int remaining;
+
+ ent.client.ps.blend[0] = ent.client.ps.blend[1] = ent.client.ps.blend[2] = ent.client.ps.blend[3] = 0;
+
+ // add for contents
+ VectorAdd(ent.s.origin, ent.client.ps.viewoffset, vieworg);
+ contents = gi.pointcontents.pointcontents(vieworg);
+ if ((contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) != 0)
+ ent.client.ps.rdflags |= RDF_UNDERWATER;
+ else
+ ent.client.ps.rdflags &= ~RDF_UNDERWATER;
+
+ if ((contents & (CONTENTS_SOLID | CONTENTS_LAVA)) != 0)
+ SV_AddBlend(1.0f, 0.3f, 0.0f, 0.6f, ent.client.ps.blend);
+ else if ((contents & CONTENTS_SLIME) != 0)
+ SV_AddBlend(0.0f, 0.1f, 0.05f, 0.6f, ent.client.ps.blend);
+ else if ((contents & CONTENTS_WATER) != 0)
+ SV_AddBlend(0.5f, 0.3f, 0.2f, 0.4f, ent.client.ps.blend);
+
+ // add for powerups
+ if (ent.client.quad_framenum > level.framenum) {
+ remaining = (int) (ent.client.quad_framenum - level.framenum);
+ if (remaining == 30) // beginning to fade
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(0, 0, 1, 0.08f, ent.client.ps.blend);
+ }
+ else if (ent.client.invincible_framenum > level.framenum) {
+ remaining = (int) ent.client.invincible_framenum - level.framenum;
+ if (remaining == 30) // beginning to fade
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(1, 1, 0, 0.08f, ent.client.ps.blend);
+ }
+ else if (ent.client.enviro_framenum > level.framenum) {
+ remaining = (int) ent.client.enviro_framenum - level.framenum;
+ if (remaining == 30) // beginning to fade
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(0, 1, 0, 0.08f, ent.client.ps.blend);
+ }
+ else if (ent.client.breather_framenum > level.framenum) {
+ remaining = (int) ent.client.breather_framenum - level.framenum;
+ if (remaining == 30) // beginning to fade
+ gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(0.4f, 1, 0.4f, 0.04f, ent.client.ps.blend);
+ }
+
+ // add for damage
+ if (ent.client.damage_alpha > 0)
+ SV_AddBlend(
+ ent.client.damage_blend[0],
+ ent.client.damage_blend[1],
+ ent.client.damage_blend[2],
+ ent.client.damage_alpha,
+ ent.client.ps.blend);
+
+ if (ent.client.bonus_alpha > 0)
+ SV_AddBlend(0.85f, 0.7f, 0.3f, ent.client.bonus_alpha, ent.client.ps.blend);
+
+ // drop the damage value
+ ent.client.damage_alpha -= 0.06;
+ if (ent.client.damage_alpha < 0)
+ ent.client.damage_alpha = 0;
+
+ // drop the bonus value
+ ent.client.bonus_alpha -= 0.1;
+ if (ent.client.bonus_alpha < 0)
+ ent.client.bonus_alpha = 0;
+ }
+
+ /*
+ =================
+ P_FallingDamage
+ =================
+ */
+ public static void P_FallingDamage(edict_t ent) {
+ float delta;
+ int damage;
+ float[] dir = { 0, 0, 0 };
+
+ if (ent.s.modelindex != 255)
+ return; // not in the player model
+
+ if (ent.movetype == MOVETYPE_NOCLIP)
+ return;
+
+ if ((ent.client.oldvelocity[2] < 0) && (ent.velocity[2] > ent.client.oldvelocity[2]) && (null == ent.groundentity)) {
+ delta = ent.client.oldvelocity[2];
+ }
+ else {
+ if (ent.groundentity == null)
+ return;
+ delta = ent.velocity[2] - ent.client.oldvelocity[2];
+ }
+ delta = delta * delta * 0.0001f;
+
+ // never take falling damage if completely underwater
+ if (ent.waterlevel == 3)
+ return;
+ if (ent.waterlevel == 2)
+ delta *= 0.25;
+ if (ent.waterlevel == 1)
+ delta *= 0.5;
+
+ if (delta < 1)
+ return;
+
+ if (delta < 15) {
+ ent.s.event = EV_FOOTSTEP;
+ return;
+ }
+
+ ent.client.fall_value = delta * 0.5f;
+ if (ent.client.fall_value > 40)
+ ent.client.fall_value = 40;
+ ent.client.fall_time = level.time + FALL_TIME;
+
+ if (delta > 30) {
+ if (ent.health > 0) {
+ if (delta >= 55)
+ ent.s.event = EV_FALLFAR;
+ else
+ ent.s.event = EV_FALL;
+ }
+ ent.pain_debounce_time = level.time; // no normal pain sound
+ damage = (int) ((delta - 30) / 2);
+ if (damage < 1)
+ damage = 1;
+ VectorSet(dir, 0, 0, 1);
+
+ if (deathmatch.value == 0 || 0 == ((int) dmflags.value & DF_NO_FALLING))
+ T_Damage(ent, g_edicts[0], g_edicts[0], dir, ent.s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
+ }
+ else {
+ ent.s.event = EV_FALLSHORT;
+ return;
+ }
+ }
+
+ /*
+ =============
+ P_WorldEffects
+ =============
+ */
+ public static void P_WorldEffects() {
+ boolean breather;
+ boolean envirosuit;
+ int waterlevel, old_waterlevel;
+
+ if (current_player.movetype == MOVETYPE_NOCLIP) {
+ current_player.air_finished = level.time + 12; // don't need air
+ return;
+ }
+
+ waterlevel = current_player.waterlevel;
+ old_waterlevel = current_client.old_waterlevel;
+ current_client.old_waterlevel = waterlevel;
+
+ breather = current_client.breather_framenum > level.framenum;
+ envirosuit = current_client.enviro_framenum > level.framenum;
+
+ //
+ // if just entered a water volume, play a sound
+ //
+ if (old_waterlevel == 0 && waterlevel != 0) {
+ PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
+ if ((current_player.watertype & CONTENTS_LAVA) != 0)
+ gi.sound(current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
+ else if ((current_player.watertype & CONTENTS_SLIME) != 0)
+ gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+ else if ((current_player.watertype & CONTENTS_WATER) != 0)
+ gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
+ current_player.flags |= FL_INWATER;
+
+ // clear damage_debounce, so the pain sound will play immediately
+ current_player.damage_debounce_time = level.time - 1;
+ }
+
+ //
+ // if just completely exited a water volume, play a sound
+ //
+ if (old_waterlevel != 0 && waterlevel == 0) {
+ PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
+ gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
+ current_player.flags &= ~FL_INWATER;
+ }
+
+ //
+ // check for head just going under water
+ //
+ if (old_waterlevel != 3 && waterlevel == 3) {
+ gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
+ }
+
+ //
+ // check for head just coming out of water
+ //
+ if (old_waterlevel == 3 && waterlevel != 3) {
+ if (current_player.air_finished < level.time) { // gasp for air
+ gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
+ PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
+ }
+ else if (current_player.air_finished < level.time + 11) { // just break surface
+ gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
+ }
+ }
+
+ //
+ // check for drowning
+ //
+ if (waterlevel == 3) {
+ // breather or envirosuit give air
+ if (breather || envirosuit) {
+ current_player.air_finished = level.time + 10;
+
+ if (((int) (current_client.breather_framenum - level.framenum) % 25) == 0) {
+ if (current_client.breather_sound == 0)
+ gi.sound(current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
+ else
+ gi.sound(current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
+ current_client.breather_sound ^= 1;
+ PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
+ //FIXME: release a bubble?
+ }
+ }
+
+ // if out of air, start drowning
+ if (current_player.air_finished < level.time) { // drown!
+ if (current_player.client.next_drown_time < level.time && current_player.health > 0) {
+ current_player.client.next_drown_time = level.time + 1;
+
+ // take more damage the longer underwater
+ current_player.dmg += 2;
+ if (current_player.dmg > 15)
+ current_player.dmg = 15;
+
+ // play a gurp sound instead of a normal pain sound
+ if (current_player.health <= current_player.dmg)
+ gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
+ else if ((rand() & 1) != 0)
+ gi.sound(current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
+ else
+ gi.sound(current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
+
+ current_player.pain_debounce_time = level.time;
+
+ T_Damage(
+ current_player,
+ g_edicts[0],
+ g_edicts[0],
+ vec3_origin,
+ current_player.s.origin,
+ vec3_origin,
+ current_player.dmg,
+ 0,
+ DAMAGE_NO_ARMOR,
+ MOD_WATER);
+ }
+ }
+ }
+ else {
+ current_player.air_finished = level.time + 12;
+ current_player.dmg = 2;
+ }
+
+ //
+ // check for sizzle damage
+ //
+ if (waterlevel != 0 && 0 != (current_player.watertype & (CONTENTS_LAVA | CONTENTS_SLIME))) {
+ if ((current_player.watertype & CONTENTS_LAVA) != 0) {
+ if (current_player.health > 0
+ && current_player.pain_debounce_time <= level.time
+ && current_client.invincible_framenum < level.framenum) {
+ if ((rand() & 1) != 0)
+ gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
+ else
+ gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
+ current_player.pain_debounce_time = level.time + 1;
+ }
+
+ if (envirosuit) // take 1/3 damage with envirosuit
+ T_Damage(
+ current_player,
+ g_edicts[0],
+ g_edicts[0],
+ vec3_origin,
+ current_player.s.origin,
+ vec3_origin,
+ 1 * waterlevel,
+ 0,
+ 0,
+ MOD_LAVA);
+ else
+ T_Damage(
+ current_player,
+ g_edicts[0],
+ g_edicts[0],
+ vec3_origin,
+ current_player.s.origin,
+ vec3_origin,
+ 3 * waterlevel,
+ 0,
+ 0,
+ MOD_LAVA);
+ }
+
+ if ((current_player.watertype & CONTENTS_SLIME) != 0) {
+ if (!envirosuit) { // no damage from slime with envirosuit
+ T_Damage(
+ current_player,
+ g_edicts[0],
+ g_edicts[0],
+ vec3_origin,
+ current_player.s.origin,
+ vec3_origin,
+ 1 * waterlevel,
+ 0,
+ 0,
+ MOD_SLIME);
+ }
+ }
+ }
+ }
+
+ /*
+ ===============
+ G_SetClientEffects
+ ===============
+ */
+ public static void G_SetClientEffects(edict_t ent) {
+ int pa_type;
+ int remaining;
+
+ ent.s.effects = 0;
+ ent.s.renderfx = 0;
+
+ if (ent.health <= 0 || level.intermissiontime != 0)
+ return;
+
+ if (ent.powerarmor_time > level.time) {
+ pa_type = PowerArmorType(ent);
+ if (pa_type == POWER_ARMOR_SCREEN) {
+ ent.s.effects |= EF_POWERSCREEN;
+ }
+ else if (pa_type == POWER_ARMOR_SHIELD) {
+ ent.s.effects |= EF_COLOR_SHELL;
+ ent.s.renderfx |= RF_SHELL_GREEN;
+ }
+ }
+
+ if (ent.client.quad_framenum > level.framenum) {
+ remaining = (int) ent.client.quad_framenum - level.framenum;
+ if (remaining > 30 || 0 != (remaining & 4))
+ ent.s.effects |= EF_QUAD;
+ }
+
+ if (ent.client.invincible_framenum > level.framenum) {
+ remaining = (int) ent.client.invincible_framenum - level.framenum;
+ if (remaining > 30 || 0 != (remaining & 4))
+ ent.s.effects |= EF_PENT;
+ }
+
+ // show cheaters!!!
+ if ((ent.flags & FL_GODMODE) != 0) {
+ ent.s.effects |= EF_COLOR_SHELL;
+ ent.s.renderfx |= (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE);
+ }
+ }
+
+ /*
+ ===============
+ G_SetClientEvent
+ ===============
+ */
+ public static void G_SetClientEvent(edict_t ent) {
+ if (ent.s.event != 0)
+ return;
+
+ if (ent.groundentity != null && xyspeed > 225) {
+ if ((int) (current_client.bobtime + bobmove) != bobcycle)
+ ent.s.event = EV_FOOTSTEP;
+ }
+ }
+
+ /*
+ ===============
+ G_SetClientSound
+ ===============
+ */
+ public static void G_SetClientSound(edict_t ent) {
+ String weap;
+
+ if (ent.client.pers.game_helpchanged != game.helpchanged) {
+ ent.client.pers.game_helpchanged = game.helpchanged;
+ ent.client.pers.helpchanged = 1;
+ }
+
+ // help beep (no more than three times)
+ if (ent.client.pers.helpchanged != 0 && ent.client.pers.helpchanged <= 3 && 0 == (level.framenum & 63)) {
+ ent.client.pers.helpchanged++;
+ gi.sound(ent, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
+ }
+
+ if (ent.client.pers.weapon != null)
+ weap = ent.client.pers.weapon.classname;
+ else
+ weap = "";
+
+ if (ent.waterlevel != 0 && 0 != (ent.watertype & (CONTENTS_LAVA | CONTENTS_SLIME)))
+ ent.s.sound = snd_fry;
+ else if (strcmp(weap, "weapon_railgun") == 0)
+ ent.s.sound = gi.soundindex("weapons/rg_hum.wav");
+ else if (strcmp(weap, "weapon_bfg") == 0)
+ ent.s.sound = gi.soundindex("weapons/bfg_hum.wav");
+ else if (ent.client.weapon_sound != 0)
+ ent.s.sound = ent.client.weapon_sound;
+ else
+ ent.s.sound = 0;
+ }
+
+ /*
+ ===============
+ G_SetClientFrame
+ ===============
+ */
+ public static void G_SetClientFrame(edict_t ent) {
+ gclient_t client;
+ boolean duck, run;
+
+ if (ent.s.modelindex != 255)
+ return; // not in the player model
+
+ client = ent.client;
+
+ if ((client.ps.pmove.pm_flags & PMF_DUCKED)!=0)
+ duck = true;
+ else
+ duck = false;
+ if (xyspeed!=0)
+ run = true;
+ else
+ run = false;
+
+ boolean skip = false;
+ // check for stand/duck and stop/go transitions
+ if (duck != client.anim_duck && client.anim_priority < ANIM_DEATH)
+ skip = true;
+
+ if (run != client.anim_run && client.anim_priority == ANIM_BASIC)
+ skip = true;
+
+ if (null==ent.groundentity && client.anim_priority <= ANIM_WAVE)
+ skip = true;
+
+ if (!skip) {
+ if (client.anim_priority == ANIM_REVERSE) {
+ if (ent.s.frame > client.anim_end) {
+ ent.s.frame--;
+ return;
+ }
+ }
+ else if (ent.s.frame < client.anim_end) { // continue an animation
+ ent.s.frame++;
+ return;
+ }
+
+ if (client.anim_priority == ANIM_DEATH)
+ return; // stay there
+ if (client.anim_priority == ANIM_JUMP) {
+ if (null==ent.groundentity)
+ return; // stay there
+ ent.client.anim_priority = ANIM_WAVE;
+ ent.s.frame = FRAME_jump3;
+ ent.client.anim_end = FRAME_jump6;
+ return;
+ }
+ }
+
+ // return to either a running or standing frame
+ client.anim_priority = ANIM_BASIC;
+ client.anim_duck = duck;
+ client.anim_run = run;
+
+ if (null==ent.groundentity) {
+ client.anim_priority = ANIM_JUMP;
+ if (ent.s.frame != FRAME_jump2)
+ ent.s.frame = FRAME_jump1;
+ client.anim_end = FRAME_jump2;
+ }
+ else if (run) { // running
+ if (duck) {
+ ent.s.frame = FRAME_crwalk1;
+ client.anim_end = FRAME_crwalk6;
+ }
+ else {
+ ent.s.frame = FRAME_run1;
+ client.anim_end = FRAME_run6;
+ }
+ }
+ else { // standing
+ if (duck) {
+ ent.s.frame = FRAME_crstnd01;
+ client.anim_end = FRAME_crstnd19;
+ }
+ else {
+ ent.s.frame = FRAME_stand01;
+ client.anim_end = FRAME_stand40;
+ }
+ }
+ }
+
+ /*
+ =================
+ ClientEndServerFrame
+
+ Called for each player at the end of the server frame
+ and right after spawning
+ =================
+ */
+ public static void ClientEndServerFrame(edict_t ent) {
+ float bobtime;
+ int i;
+
+ current_player = ent;
+ current_client = ent.client;
+
+ //
+ // If the origin or velocity have changed since ClientThink(),
+ // update the pmove values. This will happen when the client
+ // is pushed by a bmodel or kicked by an explosion.
+ //
+ // If it wasn't updated here, the view position would lag a frame
+ // behind the body position when pushed -- "sinking into plats"
+ //
+ for (i = 0; i < 3; i++) {
+ current_client.ps.pmove.origin[i] = (short) (ent.s.origin[i] * 8.0);
+ current_client.ps.pmove.velocity[i] = (short) (ent.velocity[i] * 8.0);
+ }
+
+ //
+ // If the end of unit layout is displayed, don't give
+ // the player any normal movement attributes
+ //
+ if (level.intermissiontime!=0) {
+ // FIXME: add view drifting here?
+ current_client.ps.blend[3] = 0;
+ current_client.ps.fov = 90;
+ G_SetStats(ent);
+ return;
+ }
+
+ AngleVectors(ent.client.v_angle, forward, right, up);
+
+ // burn from lava, etc
+ P_WorldEffects();
+
+ //
+ // set model angles from view angles so other things in
+ // the world can tell which direction you are looking
+ //
+ if (ent.client.v_angle[PITCH] > 180)
+ ent.s.angles[PITCH] = (-360 + ent.client.v_angle[PITCH]) / 3;
+ else
+ ent.s.angles[PITCH] = ent.client.v_angle[PITCH] / 3;
+ ent.s.angles[YAW] = ent.client.v_angle[YAW];
+ ent.s.angles[ROLL] = 0;
+ ent.s.angles[ROLL] = SV_CalcRoll(ent.s.angles, ent.velocity) * 4;
+
+ //
+ // calculate speed and cycle to be used for
+ // all cyclic walking effects
+ //
+ xyspeed = (float) Math.sqrt(ent.velocity[0] * ent.velocity[0] + ent.velocity[1] * ent.velocity[1]);
+
+ if (xyspeed < 5) {
+ bobmove = 0;
+ current_client.bobtime = 0; // start at beginning of cycle again
+ }
+ else if (ent.groundentity!=null) { // so bobbing only cycles when on ground
+ if (xyspeed > 210)
+ bobmove = 0.25f;
+ else if (xyspeed > 100)
+ bobmove = 0.125f;
+ else
+ bobmove = 0.0625f;
+ }
+
+ bobtime = (current_client.bobtime += bobmove);
+
+ if ((current_client.ps.pmove.pm_flags & PMF_DUCKED)!=0)
+ bobtime *= 4;
+
+ bobcycle = (int) bobtime;
+ bobfracsin = (float) Math.abs(Math.sin(bobtime * Math.PI));
+
+ // detect hitting the floor
+ P_FallingDamage(ent);
+
+ // apply all the damage taken this frame
+ P_DamageFeedback(ent);
+
+ // determine the view offsets
+ SV_CalcViewOffset(ent);
+
+ // determine the gun offsets
+ SV_CalcGunOffset(ent);
+
+ // determine the full screen color blend
+ // must be after viewoffset, so eye contents can be
+ // accurately determined
+ // FIXME: with client prediction, the contents
+ // should be determined by the client
+ SV_CalcBlend(ent);
+
+ // chase cam stuff
+ if (ent.client.resp.spectator)
+ G_SetSpectatorStats(ent);
+ else
+ G_SetStats(ent);
+ G_CheckChaseStats(ent);
+
+ G_SetClientEvent(ent);
+
+ G_SetClientEffects(ent);
+
+ G_SetClientSound(ent);
+
+ G_SetClientFrame(ent);
+
+ VectorCopy(ent.velocity, ent.client.oldvelocity);
+ VectorCopy(ent.client.ps.viewangles, ent.client.oldviewangles);
+
+ // clear weapon kicks
+ VectorClear(ent.client.kick_origin);
+ VectorClear(ent.client.kick_angles);
+
+ // if the scoreboard is up, update it
+ if (ent.client.showscores && 0==(level.framenum & 31)) {
+ DeathmatchScoreboardMessage(ent, ent.enemy);
+ gi.unicast(ent, false);
+ }
+ }
+}
diff --git a/src/jake2/game/SuperAdapter.java b/src/jake2/game/SuperAdapter.java
new file mode 100644
index 0000000..67285aa
--- /dev/null
+++ b/src/jake2/game/SuperAdapter.java
@@ -0,0 +1,69 @@
+/*
+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 09.01.2004 by RST.
+// $Id: SuperAdapter.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+package jake2.game;
+
+import jake2.qcommon.Com;
+
+import java.util.Vector;
+
+
+// import jake2.*;
+// import jake2.client.*;
+// import jake2.game.*;
+// import jake2.qcommon.*;
+// import jake2.render.*;
+// import jake2.server.*;
+
+public class SuperAdapter {
+
+ // registration
+ private static void register(SuperAdapter sa)
+ {
+ adapters.add(sa);
+ //Com.Println("registering adapter " + sa.getID() + " (" + sa.getClass().getSuperclass() + ")");
+ }
+
+ private static int id=0;
+ private static Vector adapters = new Vector();
+
+
+ private static SuperAdapter find(int num)
+ {
+ return (SuperAdapter) adapters.elementAt(num);
+ }
+
+ // constructor
+ public SuperAdapter()
+ {
+ adapterid = id++;
+ register(this);
+ }
+
+ public int getID()
+ {
+ return adapterid;
+ }
+
+ private int adapterid;
+}
diff --git a/src/jake2/game/Swap.java b/src/jake2/game/Swap.java
new file mode 100644
index 0000000..3a074b1
--- /dev/null
+++ b/src/jake2/game/Swap.java
@@ -0,0 +1,46 @@
+/*
+ * Swap.java
+ * Copyright (C) 2003
+ *
+ * $Id: Swap.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.game;
+
+import java.nio.ByteOrder;
+
+import jake2.Globals;
+
+/**
+ * Swap
+ */
+public final class Swap {
+
+ public static void Init() {
+ // set the byte swapping variables in a portable manner
+ if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
+ Globals.endian= new BigEndianHandler();
+ } else {
+ Globals.endian= new LittleEndianHandler();
+ }
+ }
+
+}
diff --git a/src/jake2/game/client_persistant_t.java b/src/jake2/game/client_persistant_t.java
new file mode 100644
index 0000000..50ee120
--- /dev/null
+++ b/src/jake2/game/client_persistant_t.java
@@ -0,0 +1,150 @@
+/*
+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 31.10.2003 by RST.
+// $Id: client_persistant_t.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+package jake2.game;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import jake2.*;
+import jake2.*;
+import jake2.util.Lib;
+
+public class client_persistant_t implements Cloneable {
+
+ public client_persistant_t getClone() {
+ try {
+ return (client_persistant_t) this.clone();
+ }
+ catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ // client data that stays across multiple level loads
+ String userinfo = "";
+ String netname = "";
+ int hand;
+
+ boolean connected; // a loadgame will leave valid entities that
+ // just don't have a connection yet
+
+ // values saved and restored from edicts when changing levels
+ int health;
+ int max_health;
+ int savedFlags;
+
+ int selected_item;
+ int inventory[] = new int[Defines.MAX_ITEMS];
+
+ // ammo capacities
+ int max_bullets;
+ int max_shells;
+ int max_rockets;
+ int max_grenades;
+ int max_cells;
+ int max_slugs;
+
+ //pointer
+ gitem_t weapon;
+ //pointer
+ gitem_t lastweapon;
+
+ int power_cubes; // used for tracking the cubes in coop games
+ int score; // for calculating total unit score in coop games
+
+ int game_helpchanged;
+ int helpchanged;
+
+ boolean spectator; // client is a spectator
+
+ public void load(ByteBuffer bb) throws IOException {
+ // client persistant_t
+
+ userinfo = Lib.readString(bb, Defines.MAX_INFO_STRING);
+ netname = Lib.readString(bb, 16);
+
+ hand = bb.getInt();
+
+ connected = bb.getInt() != 0;
+ health = bb.getInt();
+
+ max_health = bb.getInt();
+ savedFlags = bb.getInt();
+ selected_item = bb.getInt();
+
+ for (int n = 0; n < Defines.MAX_ITEMS; n++)
+ inventory[n] = bb.getInt();
+
+ max_bullets = bb.getInt();
+ max_shells = bb.getInt();
+ max_rockets = bb.getInt();
+ max_grenades = bb.getInt();
+ max_cells = bb.getInt();
+ max_slugs = bb.getInt();
+
+ weapon = GameTarget.itemlist[bb.getInt()];
+ lastweapon = GameTarget.itemlist[bb.getInt()];
+ power_cubes = bb.getInt();
+ score = bb.getInt();
+
+ game_helpchanged = bb.getInt();
+ helpchanged = bb.getInt();
+ spectator = bb.getInt() != 0;
+
+ }
+
+ public void dump() {
+ // client persistant_t
+
+ System.out.println("userinfo: " + userinfo);
+ System.out.println("netname: " + netname);
+
+ System.out.println("hand: " + hand);
+
+ System.out.println("connected: " + connected);
+ System.out.println("health: " + health);
+
+ System.out.println("max_health: " + max_health);
+ System.out.println("savedFlags: " + savedFlags);
+ System.out.println("selected_item: " + selected_item);
+
+ for (int n = 0; n < Defines.MAX_ITEMS; n++)
+ System.out.println("inventory[" + n + "]: " + inventory[n]);
+
+ System.out.println("max_bullets: " + max_bullets);
+ System.out.println("max_shells: " + max_shells);
+ System.out.println("max_rockets: " + max_rockets);
+ System.out.println("max_grenades: " + max_grenades);
+ System.out.println("max_cells: " + max_cells);
+ System.out.println("max_slugs: " + max_slugs);
+ System.out.println("weapon: " + weapon);
+ System.out.println("lastweapon: " + lastweapon);
+ System.out.println("powercubes: " + power_cubes);
+ System.out.println("score: " + score);
+
+ System.out.println("gamehelpchanged: " + game_helpchanged);
+ System.out.println("helpchanged: " + helpchanged);
+ System.out.println("spectator: " + spectator);
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/client_respawn_t.java b/src/jake2/game/client_respawn_t.java
new file mode 100644
index 0000000..ae89e89
--- /dev/null
+++ b/src/jake2/game/client_respawn_t.java
@@ -0,0 +1,71 @@
+/*
+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 31.10.2003 by RST.
+// $Id: client_respawn_t.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+package jake2.game;
+
+import jake2.qcommon.Com;
+import jake2.util.Lib;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class client_respawn_t
+// client data that stays across deathmatch respawns
+{
+ client_persistant_t coop_respawn= new client_persistant_t(); // what to set client->pers to on a respawn
+ int enterframe; // level.framenum the client entered the game
+ int score; // frags, etc
+ float cmd_angles[] = { 0, 0, 0 }; // angles sent over in the last command
+ boolean spectator; // client is a spectator
+
+ //ok
+ public void clear() {
+ coop_respawn = new client_persistant_t();
+ enterframe = 0;
+ score = 0;
+ cmd_angles = new float[3];
+ spectator = false;
+ }
+
+ public void load(ByteBuffer bb) throws IOException {
+ coop_respawn.load(bb);
+
+ enterframe = bb.getInt();
+ score = bb.getInt();
+
+ cmd_angles[0] = bb.getFloat();
+ cmd_angles[1] = bb.getFloat();
+ cmd_angles[2] = bb.getFloat();
+
+ spectator = bb.getInt() != 0;
+ }
+
+ public void dump() {
+ coop_respawn.dump();
+
+ Com.Println("enterframe: " + enterframe);
+ Com.Println("score: " + score);
+
+ Lib.printv("cmd_angles", cmd_angles);
+ Com.Println("spectator: " + spectator);
+ }
+}
diff --git a/src/jake2/game/cmdalias_t.java b/src/jake2/game/cmdalias_t.java
new file mode 100644
index 0000000..c52356b
--- /dev/null
+++ b/src/jake2/game/cmdalias_t.java
@@ -0,0 +1,32 @@
+/*
+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 by HOZ.
+// $Id: cmdalias_t.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+package jake2.game;
+
+/**
+ * cmdalias_t
+ */
+public final class cmdalias_t {
+ public cmdalias_t next;
+ public String name="";
+ public String value;
+}
diff --git a/src/jake2/game/cmodel_t.java b/src/jake2/game/cmodel_t.java
new file mode 100644
index 0000000..47d8243
--- /dev/null
+++ b/src/jake2/game/cmodel_t.java
@@ -0,0 +1,32 @@
+/*
+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.11.2003 by RST.
+// $Id: cmodel_t.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+
+package jake2.game;
+
+public class cmodel_t {
+ public float[] mins = { 0, 0, 0 };
+ public float[] maxs = { 0, 0, 0 };
+ public float[] origin = { 0, 0, 0 }; // for sounds or lights
+ public int headnode;
+}
diff --git a/src/jake2/game/cplane_t.java b/src/jake2/game/cplane_t.java
new file mode 100644
index 0000000..ab1f5ac
--- /dev/null
+++ b/src/jake2/game/cplane_t.java
@@ -0,0 +1,57 @@
+/*
+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 31.10.2003 by RST.
+// $Id: cplane_t.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.Lib;
+import jake2.util.Math3D;
+
+public class cplane_t {
+
+ public float normal[] = new float[3];
+ public float dist;
+ public byte type; // for fast side tests
+ public byte signbits; // signx + (signy<<1) + (signz<<1)
+ public byte pad[] = { 0, 0 };
+
+ public cplane_t getClone() {
+ cplane_t out = new cplane_t();
+ out.normal = Lib.clone(normal);
+ out.dist = dist;
+ out.type = type;
+ out.signbits = signbits;
+ out.pad = Lib.clone(pad);
+
+ return out;
+ }
+
+ public void set(cplane_t c) {
+
+ Math3D.set(normal, c.normal);
+ dist = c.dist;
+ type = c.type;
+ signbits = c.signbits;
+ pad[0] = c.pad[0];
+ pad[1] = c.pad[1];
+ }
+}
diff --git a/src/jake2/game/csurface_t.java b/src/jake2/game/csurface_t.java
new file mode 100644
index 0000000..deb877f
--- /dev/null
+++ b/src/jake2/game/csurface_t.java
@@ -0,0 +1,29 @@
+/*
+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 31.10.2003 by RST.
+// $Id: csurface_t.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+
+package jake2.game;
+public class csurface_t {
+ public String name = "";
+ public int flags;
+ public int value;
+}
diff --git a/src/jake2/game/cvar_t.java b/src/jake2/game/cvar_t.java
new file mode 100644
index 0000000..d7b1ebd
--- /dev/null
+++ b/src/jake2/game/cvar_t.java
@@ -0,0 +1,40 @@
+/*
+ * cvar_t.java
+ * Copyright (C) 2003
+ *
+ * $Id: cvar_t.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+ */
+ /*
+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.
+
+*/
+package jake2.game;
+
+/**
+ * cvar_t implements the struct cvar_t of the
+ * C version
+ */
+public final class cvar_t {
+ public String name;
+ public String string;
+ public String latched_string;
+ public int flags = 0;
+ public boolean modified = false;
+ public float value = 0.0f;
+ public cvar_t next = null;
+}
diff --git a/src/jake2/game/edict_t.java b/src/jake2/game/edict_t.java
new file mode 100644
index 0000000..0c89c87
--- /dev/null
+++ b/src/jake2/game/edict_t.java
@@ -0,0 +1,469 @@
+/*
+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.
+
+*/
+
+package jake2.game;
+
+import jake2.*;
+import jake2.util.*;
+
+public class edict_t {
+
+ public edict_t(int i) {
+
+ s.number = i;
+ index = i;
+ }
+
+ public void clear() {
+ }
+
+ // integrated entity state
+ public entity_state_t s = new entity_state_t(this);
+ public boolean inuse;
+ public int linkcount;
+
+ // FIXME: move these fields to a server private sv_entity_t
+ public link_t area = new link_t(this); // linked to a division node or leaf
+
+ public int num_clusters; // if -1, use headnode instead
+ public int clusternums[] = new int[Defines.MAX_ENT_CLUSTERS];
+ public int headnode; // unused if num_clusters != -1
+ public int areanum, areanum2;
+
+ //================================
+
+ public int svflags; // SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc
+ public float[] mins = { 0, 0, 0 };
+ public float[] maxs = { 0, 0, 0 };
+ public float[] absmin = { 0, 0, 0 };
+ public float[] absmax = { 0, 0, 0 };
+ public float[] size = { 0, 0, 0 };
+ public int solid;
+ public int clipmask;
+
+ // the game dll can add anything it wants after
+ // this point in the structure
+ // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
+ // EXPECTS THE FIELDS IN THAT ORDER!
+
+ //================================
+ public int movetype;
+ public int flags;
+
+ public String model = "";
+ public float freetime; // sv.time when the object was freed
+
+ //
+ // only used locally in game, not by server
+ //
+ public String message = "";
+ public String classname = "";
+ public int spawnflags;
+
+ public float timestamp;
+
+ // set in qe3, -1 = up, -2 = down
+ public float angle;
+
+ public String target = null;
+ public String targetname = null;
+ public String killtarget = null;
+ public String team = null;
+ public String pathtarget = null;
+ public String deathtarget = null;
+ public String combattarget = null;
+
+ public edict_t target_ent = null;
+
+ public float speed, accel, decel;
+ public float[] movedir = { 0, 0, 0 };
+
+ public float[] pos1 = { 0, 0, 0 };
+ public float[] pos2 = { 0, 0, 0 };
+
+ public float[] velocity = { 0, 0, 0 };
+ public float[] avelocity = { 0, 0, 0 };
+ public int mass;
+ public float air_finished;
+ public float gravity; // per entity gravity multiplier (1.0 is normal)
+ // use for lowgrav artifact, flares
+
+ public edict_t goalentity = null;
+ public edict_t movetarget = null;
+ public float yaw_speed;
+ public float ideal_yaw;
+
+ public float nextthink;
+
+ public EntThinkAdapter prethink = null;
+ public EntThinkAdapter think = null;
+ public EntBlockedAdapter blocked = null;
+ public EntTouchAdapter touch = null;
+ public EntUseAdapter use = null;
+ public EntPainAdapter pain = null;
+ public EntDieAdapter die = null;
+
+ public float touch_debounce_time; // are all these legit? do we need more/less of them?
+ public float pain_debounce_time;
+ public float damage_debounce_time;
+ public float fly_sound_debounce_time; //move to clientinfo
+ public float last_move_time;
+
+ public int health;
+ public int max_health;
+ public int gib_health;
+ public int deadflag;
+ public int show_hostile;
+
+ public float powerarmor_time;
+
+ public String map = null;
+ ; // target_changelevel
+
+ public int viewheight; // height above origin where eyesight is determined
+ public int takedamage;
+ public int dmg;
+ public int radius_dmg;
+ public float dmg_radius;
+ public int sounds; //make this a spawntemp var?
+ public int count;
+
+ public edict_t chain = null;
+ public edict_t enemy = null;
+ public edict_t oldenemy = null;
+ public edict_t activator = null;
+ public edict_t groundentity = null;
+ public int groundentity_linkcount;
+ public edict_t teamchain = null;
+ public edict_t teammaster = null;
+
+ public edict_t mynoise = null; // can go in client only
+ public edict_t mynoise2 = null;
+
+ public int noise_index;
+ public int noise_index2;
+ public float volume;
+ public float attenuation;
+
+ // timing variables
+ public float wait;
+ public float delay; // before firing targets
+ public float random;
+
+ public float teleport_time;
+
+ public int watertype;
+ public int waterlevel;
+
+ public float[] move_origin = { 0, 0, 0 };
+
+ public float[] move_angles = { 0, 0, 0 };
+
+ // move this to clientinfo?
+ public int light_level;
+
+ public int style; // also used as areaportal number
+
+ public gitem_t item; // for bonus items
+
+ // common integrated data blocks
+ public moveinfo_t moveinfo = new moveinfo_t();
+ public monsterinfo_t monsterinfo = new monsterinfo_t();
+
+ public gclient_t client;
+ public edict_t owner;
+
+ public int index; //introduced by rst
+
+
+ /////////////////////////////////////////////////
+
+ public boolean set(String key, String value) {
+
+ if (key.equals("classname")) {
+ classname = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("model")) {
+ model = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("spawnflags")) {
+ spawnflags = Lib.atoi(value);
+ return true;
+ } // F_INT),
+
+ if (key.equals("speed")) {
+ speed = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("accel")) {
+ accel = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("decel")) {
+ decel = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("target")) {
+ target = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("targetname")) {
+ targetname = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("pathtarget")) {
+ pathtarget = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("deathtarget")) {
+ deathtarget = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+ if (key.equals("killtarget")) {
+ killtarget = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("combattarget")) {
+ combattarget = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("message")) {
+ message = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("team")) {
+ team = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("wait")) {
+ wait = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("delay")) {
+ delay = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("random")) {
+ random = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("move_origin")) {
+ move_origin = Lib.atov(value);
+ return true;
+ } // F_VECTOR),
+
+ if (key.equals("move_angles")) {
+ move_angles = Lib.atov(value);
+ return true;
+ } // F_VECTOR),
+
+ if (key.equals("style")) {
+ style = Lib.atoi(value);
+ return true;
+ } // F_INT),
+
+ if (key.equals("count")) {
+ count = Lib.atoi(value);
+ return true;
+ } // F_INT),
+
+ if (key.equals("health")) {
+ health = Lib.atoi(value);
+ return true;
+ } // F_INT),
+
+ if (key.equals("sounds")) {
+ sounds = Lib.atoi(value);
+ return true;
+ } // F_INT),
+
+ if (key.equals("light")) {
+ return true;
+ } // F_IGNORE),
+
+ if (key.equals("dmg")) {
+ dmg = Lib.atoi(value);
+ return true;
+ } // F_INT),
+
+ if (key.equals("mass")) {
+ mass = Lib.atoi(value);
+ return true;
+ } // F_INT),
+
+ if (key.equals("volume")) {
+ volume = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("attenuation")) {
+ attenuation = Lib.atof(value);
+ return true;
+ } // F_FLOAT),
+
+ if (key.equals("map")) {
+ map = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING),
+
+ if (key.equals("origin")) {
+ s.origin = Lib.atov(value);
+ return true;
+ } // F_VECTOR),
+
+ if (key.equals("angles")) {
+ s.angles = Lib.atov(value);
+ return true;
+ } // F_VECTOR),
+
+ if (key.equals("angle")) {
+ s.angles = new float[] { 0, Lib.atof(value), 0 };
+ return true;
+ } // F_ANGLEHACK),
+
+ /* --- NOSPAWN ---
+ if (key.equals("goalentity")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+
+ if (key.equals("movetarget")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+
+ if (key.equals("enemy")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+
+ if (key.equals("oldenemy")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+
+ if (key.equals("activator")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+
+ if (key.equals("groundentity")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("teamchain")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("teammaster")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("owner")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("mynoise")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("mynoise2")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("target_ent")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("chain")) {
+ return true;
+ } // F_EDICT, FFL_NOSPAWN),
+ if (key.equals("prethink")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("think")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("blocked")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("touch")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("use")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("pain")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("die")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("stand")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("idle")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("search")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("walk")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("run")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("dodge")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("attack")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("melee")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("sight")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("checkattack")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+ if (key.equals("currentmove")) {
+ return true;
+ } // F_MMOVE, FFL_NOSPAWN),
+ if (key.equals("endfunc")) {
+ return true;
+ } // F_FUNCTION, FFL_NOSPAWN),
+
+ */
+ if (key.equals("item")) {
+ Game.gi.error("ent.set(\"item\") called.");
+ return true;
+ } // F_ITEM)
+
+ return false;
+ }
+}
diff --git a/src/jake2/game/entity_state_t.java b/src/jake2/game/entity_state_t.java
new file mode 100644
index 0000000..a606b74
--- /dev/null
+++ b/src/jake2/game/entity_state_t.java
@@ -0,0 +1,85 @@
+/*
+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 08.11.2003 by RST.
+// $Id: entity_state_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.Math3D;
+
+public class entity_state_t implements Cloneable {
+ // entity_state_t is the information conveyed from the server
+ // in an update message about entities that the client will
+ // need to render in some way
+
+
+ public entity_state_t(edict_t ent)
+ {
+ this.surrounding_ent = ent;
+ }
+
+ public int number = -99999; // edict index
+ public edict_t surrounding_ent = null;
+ public float[] origin = { 0, 0, 0 };
+ public float[] angles = { 0, 0, 0 };
+ public float[] old_origin = { 0, 0, 0 }; // for lerping
+ public int modelindex;
+ public int modelindex2, modelindex3, modelindex4; // weapons, CTF flags, etc.
+ public int frame;
+ public int skinnum;
+ public int effects; // PGM - we're filling it, so it needs to be unsigned
+ public int renderfx;
+ public int solid;
+ // for client side prediction, 8*(bits 0-4) is x/y radius
+ // 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
+ // gi.linkentity sets this properly
+ public int sound; // for looping sounds, to guarantee shutoff
+ public int event; // impulse events -- muzzle flashes, footsteps, etc
+ // events only go out for a single frame, they
+ // are automatically cleared each frame
+
+ public entity_state_t getClone()
+ {
+ entity_state_t out = new entity_state_t(this.surrounding_ent);
+ out.set(this);
+ return out;
+ }
+
+ public void set(entity_state_t from) {
+ number = from.number;
+ Math3D.VectorCopy(from.origin, origin);
+ Math3D.VectorCopy(from.angles, angles);
+ Math3D.VectorCopy(from.old_origin, old_origin);
+
+ modelindex = from.modelindex;
+ modelindex2 = from.modelindex2;
+ modelindex3 = from.modelindex3;
+ modelindex4 = from.modelindex4;
+
+ frame = from.frame;
+ skinnum = from.skinnum;
+ effects = from.effects;
+ renderfx = from.renderfx;
+ solid = from.solid;
+ sound = from.sound;
+ event = from.event;
+ }
+} \ No newline at end of file
diff --git a/src/jake2/game/field_t.java b/src/jake2/game/field_t.java
new file mode 100644
index 0000000..c880a05
--- /dev/null
+++ b/src/jake2/game/field_t.java
@@ -0,0 +1,44 @@
+/*
+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 20.11.2003 by RST
+// $Id: field_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+public class field_t {
+
+ public field_t(String name, int type, int flags) {
+
+ this.name = name;
+ this.type = type;
+ this.flags = flags;
+ }
+
+ public field_t(String name, int type) {
+
+ this.name = name;
+ this.type = type;
+ flags = 0;
+ }
+
+ public String name;
+ public int type;
+ public int flags;
+}
diff --git a/src/jake2/game/game_export_t.java b/src/jake2/game/game_export_t.java
new file mode 100644
index 0000000..4f8369c
--- /dev/null
+++ b/src/jake2/game/game_export_t.java
@@ -0,0 +1,118 @@
+/*
+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 31.10.2003 by RST.
+// $Id: game_export_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+import jake2.Defines;
+import jake2.qcommon.Com;
+
+
+//
+//functions exported by the game subsystem
+//
+
+public class game_export_t {
+
+ public int apiversion;
+
+ // the init function will only be called when a game starts,
+ // not each time a level is loaded. Persistant data for clients
+ // and the server can be allocated in init
+ public void Init() {
+ Game.InitGame();
+ }
+ public void Shutdown() {
+ Game.ShutdownGame();
+ }
+
+ // each new level entered will cause a call to SpawnEntities
+ public void SpawnEntities(String mapname, String entstring, String spawnpoint) {
+ Game.SpawnEntities(mapname, entstring, spawnpoint);
+ }
+
+ // Read/Write Game is for storing persistant cross level information
+ // about the world state and the clients.
+ // WriteGame is called every time a level is exited.
+ // ReadGame is called on a loadgame.
+ public void WriteGame(String filename, boolean autosave) {
+ Com.Error(Defines.ERR_FATAL, "WriteGame not implemnted!");
+ }
+
+ public void ReadGame(String filename) {
+ Game.ReadGame(filename);
+ }
+
+ // ReadLevel is called after the default map information has been
+ // loaded with SpawnEntities
+ public void WriteLevel(String filename) {
+ Com.Error(Defines.ERR_FATAL, "WriteLevel not implemnted!");
+ }
+
+ public void ReadLevel(String filename) {
+ Com.Error(Defines.ERR_FATAL, "ReadLevel not implemnted!");
+ }
+
+ public boolean ClientConnect(edict_t ent, String userinfo) {
+ return PlayerClient.ClientConnect(ent, userinfo);
+ }
+ public void ClientBegin(edict_t ent) {
+ PlayerClient.ClientBegin(ent);
+ }
+ public void ClientUserinfoChanged(edict_t ent, String userinfo) {
+ PlayerClient.ClientUserinfoChanged(ent, userinfo);
+ }
+ public void ClientDisconnect(edict_t ent) {
+ PlayerClient.ClientDisconnect(ent);
+ }
+ public void ClientCommand(edict_t ent) {
+ PlayerClient.ClientCommand(ent);
+ }
+
+ public void ClientThink(edict_t ent, usercmd_t cmd) {
+ PlayerClient.ClientThink(ent, cmd);
+ }
+
+ public void RunFrame() {
+ Game.G_RunFrame();
+ }
+
+ // ServerCommand will be called when an "sv <command>" command is issued on the
+ // server console.
+ // the game can issue gi.argc() / gi.argv() commands to get the rest
+ // of the parameters
+ public void ServerCommand() {
+ Game.ServerCommand();
+ }
+
+ //
+ // global variables shared between game and server
+ //
+
+ // the edict array is allocated in the game dll so it
+ // can vary in size from one game to another.
+
+ // the size will be fixed when ge.Init() is called
+ public edict_t edicts[] = Game.g_edicts;
+ public int num_edicts; // current number, <= max_edicts
+ public int max_edicts;
+}
diff --git a/src/jake2/game/game_import_t.java b/src/jake2/game/game_import_t.java
new file mode 100644
index 0000000..7ac52d5
--- /dev/null
+++ b/src/jake2/game/game_import_t.java
@@ -0,0 +1,237 @@
+/*
+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 31.10.2003 by RST.
+// $Id: game_import_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+import jake2.Defines;
+import jake2.client.SCR;
+import jake2.qcommon.CM;
+import jake2.qcommon.Cbuf;
+import jake2.qcommon.Com;
+import jake2.qcommon.Cvar;
+import jake2.qcommon.PMove;
+import jake2.server.SV;
+import jake2.server.SV_GAME;
+import jake2.server.SV_INIT;
+import jake2.server.SV_SEND;
+import jake2.server.SV_WORLD;
+
+//
+// collection of functions provided by the main engine
+//
+public class game_import_t {
+ // R S T: SEE SV_InitGameProgs() !
+
+ // special messages
+ public void bprintf(int printlevel, String s) {
+ SV_SEND.SV_BroadcastPrintf(printlevel, s);
+ }
+ public void dprintf(String s) {
+ SV_SEND.PF_dprintf(s);
+ }
+ public void cprintf(edict_t ent, int printlevel, String s) {
+ SV_GAME.PF_cprintf(ent, printlevel, s);
+ }
+ public void centerprintf(edict_t ent, String s) {
+ SV_GAME.PF_centerprintf(ent, s);
+ }
+ public void sound(edict_t ent, int channel, int soundindex, float volume, float attenuation, float timeofs) {
+ SV_GAME.PF_StartSound(ent, channel, soundindex, volume, attenuation, timeofs);
+ }
+ public void positioned_sound(
+ float[] origin,
+ edict_t ent,
+ int channel,
+ int soundinedex,
+ float volume,
+ float attenuation,
+ float timeofs) {
+
+ SV_SEND.SV_StartSound(origin, ent, channel, soundinedex, volume, attenuation, timeofs);
+ }
+
+ // config strings hold all the index strings, the lightstyles,
+ // and misc data like the sky definition and cdtrack.
+ // All of the current configstrings are sent to clients when
+ // they connect, and changes are sent to all connected clients.
+ public void configstring(int num, String string) {
+ //Com.Error(Defines.ERR_FATAL,"method is not implemented!");
+ SV_GAME.PF_Configstring(num, string);
+ }
+ public void error(String err) {
+ Com.Error(Defines.ERR_FATAL, err);
+ }
+ public void error(int level, String err) {
+ SV_GAME.PF_error(level, err);
+ }
+
+ // the *index functions create configstrings and some internal server state
+ public int modelindex(String name) {
+ return SV_INIT.SV_ModelIndex(name);
+ }
+ public int soundindex(String name) {
+ return SV_INIT.SV_SoundIndex(name);
+ }
+ public int imageindex(String name) {
+ return SV_INIT.SV_ImageIndex(name);
+ }
+ public void setmodel(edict_t ent, String name) {
+ SV_GAME.PF_setmodel(ent, name);
+ }
+
+ // collision detection
+ public trace_t trace(float[] start, float[] mins, float[] maxs, float[] end, edict_t passent, int contentmask) {
+ return SV_WORLD.SV_Trace(start, mins, maxs, end, passent, contentmask);
+ }
+
+ public pmove_t.PointContentsAdapter pointcontents;
+
+ public boolean inPVS(float[] p1, float[] p2) {
+ return SV_GAME.PF_inPVS(p1, p2);
+ }
+
+ public boolean inPHS(float[] p1, float[] p2) {
+ return SV_GAME.PF_inPHS(p1, p2);
+ }
+
+ public void SetAreaPortalState(int portalnum, boolean open) {
+ CM.CM_SetAreaPortalState(portalnum, open);
+ }
+
+ public boolean AreasConnected(int area1, int area2) {
+ return CM.CM_AreasConnected(area1, area2);
+ }
+
+ // an entity will never be sent to a client or used for collision
+ // if it is not passed to linkentity. If the size, position, or
+ // solidity changes, it must be relinked.
+ public void linkentity(edict_t ent) {
+ SV_WORLD.SV_LinkEdict(ent);
+ }
+
+ public void unlinkentity(edict_t ent) {
+ SV_WORLD.SV_UnlinkEdict(ent);
+ }
+
+ // call before removing an interactive edict
+ public int BoxEdicts(float[] mins, float[] maxs, edict_t list[], int maxcount, int areatype) {
+ return SV_WORLD.SV_AreaEdicts(mins, maxs, list, maxcount, areatype);
+ }
+
+ public void Pmove(pmove_t pmove) {
+ PMove.Pmove(pmove);
+ }
+
+ // player movement code common with client prediction
+ // network messaging
+ public void multicast(float[] origin, int to) {
+ SV_SEND.SV_Multicast(origin, to);
+ }
+
+ public void unicast(edict_t ent, boolean reliable) {
+ SV_GAME.PF_Unicast(ent, reliable);
+ }
+
+ public void WriteChar(int c) {
+ SV_GAME.PF_WriteChar(c);
+ }
+
+ public void WriteByte(int c) {
+ SV_GAME.PF_WriteByte(c);
+ }
+
+ public void WriteShort(int c) {
+ SV_GAME.PF_WriteShort(c);
+ }
+
+ public void WriteLong(int c) {
+ SV_GAME.PF_WriteLong(c);
+ }
+
+ public void WriteFloat(float f) {
+ SV_GAME.PF_WriteFloat(f);
+ }
+
+ public void WriteString(String s) {
+ SV_GAME.PF_WriteString(s);
+ }
+
+ public void WritePosition(float[] pos) {
+ SV_GAME.PF_WritePos(pos);
+ }
+ // some fractional bits
+ public void WriteDir(float[] pos) {
+ SV_GAME.PF_WriteDir(pos);
+ }
+ // single byte encoded, very coarse
+ public void WriteAngle(float f) {
+ Com.Error(Defines.ERR_FATAL, "method is not implemented!");
+ }
+
+ // managed memory allocation
+ public void TagMalloc(int size, int tag) {
+ Com.Error(Defines.ERR_FATAL, "method is not implemented!");
+ }
+ public void TagFree(Object block) {
+ Com.Error(Defines.ERR_FATAL, "method is not implemented!");
+ }
+ public void FreeTags(int tag) {
+ Com.Error(Defines.ERR_FATAL, "method is not implemented!");
+ }
+
+ // console variable interaction
+ public cvar_t cvar(String var_name, String value, int flags) {
+ return Cvar.Get(var_name, value, flags);
+ }
+
+ public cvar_t cvar_set(String var_name, String value) {
+ return Cvar.Set(var_name, value);
+ //return null;
+ }
+ public cvar_t cvar_forceset(String var_name, String value) {
+ return Cvar.ForceSet(var_name, value);
+ }
+
+ // ClientCommand and ServerCommand parameter access
+ public int argc() {
+ return Cmd.Argc();
+ }
+ public String argv(int n) {
+ return Cmd.Argv(n);
+ }
+ // concatenation of all argv >= 1
+
+ public String args() {
+ return Cmd.Args();
+ }
+
+ // add commands to the server console as if they were typed in
+ // for map changing, etc
+ public void AddCommandString(String text) {
+ Cbuf.AddText(text);
+ }
+
+ public void DebugGraph(float value, int color) {
+ SCR.DebugGraph(value, color);
+ }
+}
diff --git a/src/jake2/game/game_locals_t.java b/src/jake2/game/game_locals_t.java
new file mode 100644
index 0000000..00d56d5
--- /dev/null
+++ b/src/jake2/game/game_locals_t.java
@@ -0,0 +1,95 @@
+/*
+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 31.10.2003 by RST.
+// $Id: game_locals_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+import jake2.Defines;
+import jake2.qcommon.Com;
+import jake2.util.Lib;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class game_locals_t extends Defines {
+ //
+ // this structure is left intact through an entire game
+ // it should be initialized at dll load time, and read/written to
+ // the server.ssv file for savegames
+ //
+
+ public String helpmessage1="";
+ public String helpmessage2="";
+ public int helpchanged; // flash F1 icon if non 0, play sound
+ // and increment only if 1, 2, or 3
+
+ public gclient_t clients[] = new gclient_t[MAX_CLIENTS];
+
+ // can't store spawnpoint in level, because
+ // it would get overwritten by the savegame restore
+ public String spawnpoint = ""; // needed for coop respawns
+
+ // store latched cvars here that we want to get at often
+ public int maxclients;
+ public int maxentities;
+
+ // cross level triggers
+ public int serverflags;
+
+ // items
+ public int num_items;
+ public boolean autosaved;
+
+ public void load(ByteBuffer bb) throws IOException {
+ String date = Lib.readString(bb, 16);
+
+ helpmessage1 = Lib.readString(bb, 512);
+ helpmessage2 = Lib.readString(bb, 512);
+
+ helpchanged = bb.getInt();
+ // gclient_t*
+ bb.getInt();
+ spawnpoint = Lib.readString(bb, 512);
+ maxclients = bb.getInt();
+ maxentities = bb.getInt();
+ serverflags = bb.getInt();
+ num_items = bb.getInt();
+ autosaved = bb.getInt() != 0;
+
+ }
+
+ public void dump() {
+
+ Com.Println("String helpmessage1: " + helpmessage1);
+ Com.Println("String helpmessage2: " + helpmessage2);
+
+ Com.Println("spawnpoit: " + spawnpoint);
+ Com.Println("maxclients: " + maxclients);
+ Com.Println("maxentities: " + maxentities);
+ Com.Println("serverflags: " + serverflags);
+ Com.Println("numitems: " + num_items);
+ Com.Println("autosaved: " + autosaved);
+
+ for (int i = 0; i < maxclients; i++)
+ clients[i].dump();
+ }
+}
diff --git a/src/jake2/game/gclient_t.java b/src/jake2/game/gclient_t.java
new file mode 100644
index 0000000..ccad5aa
--- /dev/null
+++ b/src/jake2/game/gclient_t.java
@@ -0,0 +1,323 @@
+/*
+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 31.10.2003 by RST.
+// $Id: gclient_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+import jake2.qcommon.Com;
+import jake2.util.Lib;
+
+import java.awt.event.ItemListener;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class gclient_t {
+
+ public gclient_t(int index) {
+ this.index = index;
+ }
+ // this structure is cleared on each PutClientInServer(),
+ // except for 'client->pers'
+
+ // known to server
+ public player_state_t ps = new player_state_t(); // communicated by server to clients
+ public int ping;
+
+ // private to game
+ public client_persistant_t pers= new client_persistant_t();
+ public client_respawn_t resp= new client_respawn_t();
+ public pmove_state_t old_pmove= new pmove_state_t(); // for detecting out-of-pmove changes
+
+ public boolean showscores; // set layout stat
+ public boolean showinventory; // set layout stat
+ public boolean showhelp;
+ public boolean showhelpicon;
+
+ public int ammo_index;
+
+ public int buttons;
+ public int oldbuttons;
+ public int latched_buttons;
+
+ public boolean weapon_thunk;
+
+ public gitem_t newweapon;
+
+ // sum up damage over an entire frame, so
+ // shotgun blasts give a single big kick
+ public int damage_armor; // damage absorbed by armor
+ public int damage_parmor; // damage absorbed by power armor
+ public int damage_blood; // damage taken out of health
+ public int damage_knockback; // impact damage
+ public float[] damage_from = { 0, 0, 0 }; // origin for vector calculation
+
+ public float killer_yaw; // when dead, look at killer
+
+ public int weaponstate;
+ public float[] kick_angles = { 0, 0, 0 }; // weapon kicks
+ public float[] kick_origin = { 0, 0, 0 };
+ public float v_dmg_roll, v_dmg_pitch, v_dmg_time; // damage kicks
+ public float fall_time, fall_value; // for view drop on fall
+ public float damage_alpha;
+ public float bonus_alpha;
+ public float[] damage_blend = { 0, 0, 0 };
+ public float[] v_angle = { 0, 0, 0 }; // aiming direction
+ public float bobtime; // so off-ground doesn't change it
+ public float[] oldviewangles = { 0, 0, 0 };
+ public float[] oldvelocity = { 0, 0, 0 };
+
+ public float next_drown_time;
+ public int old_waterlevel;
+ public int breather_sound;
+
+ public int machinegun_shots; // for weapon raising
+
+ // animation vars
+ public int anim_end;
+ public int anim_priority;
+ public boolean anim_duck;
+ public boolean anim_run;
+
+ // powerup timers
+ public float quad_framenum;
+ public float invincible_framenum;
+ public float breather_framenum;
+ public float enviro_framenum;
+
+ public boolean grenade_blew_up;
+ public float grenade_time;
+ public int silencer_shots;
+ public int weapon_sound;
+
+ public float pickup_msg_time;
+
+ public float flood_locktill; // locked from talking
+ public float flood_when[] = new float[10]; // when messages were said
+ public int flood_whenhead; // head pointer for when said
+
+ public float respawn_time; // can respawn when time > this
+
+ public edict_t chase_target; // player we are chasing
+ public boolean update_chase; // need to update chase info?
+
+ public int index;
+
+ public void clear() {
+ }
+
+ public void load(ByteBuffer bb) throws IOException{
+
+ ps.load(bb);
+
+ ping = bb.getInt();
+
+ pers.load(bb);
+ resp.load(bb);
+
+ old_pmove.load(bb);
+
+ showscores=bb.getInt()!=0;
+ showinventory=bb.getInt()!=0;
+ showhelp=bb.getInt()!=0;
+ showhelpicon=bb.getInt()!=0;
+ ammo_index=bb.getInt();
+
+ buttons=bb.getInt();
+ oldbuttons=bb.getInt();
+ latched_buttons=bb.getInt();
+
+
+ //weapon_thunk=bb.getInt()!=0;
+ bb.getInt();
+ //newweapon=GameTarget.itemlist[bb.getInt()];
+ bb.getInt();
+
+ damage_armor=bb.getInt();
+ damage_parmor=bb.getInt();
+ damage_blood=bb.getInt();
+ damage_knockback=bb.getInt();
+
+ damage_from[0]=bb.getFloat();
+ damage_from[1]=bb.getFloat();
+ damage_from[2]=bb.getFloat();
+
+ killer_yaw=bb.getFloat();
+
+ weaponstate=bb.getInt();
+
+ kick_angles[0]=bb.getFloat();
+ kick_angles[1]=bb.getFloat();
+ kick_angles[2]=bb.getFloat();
+
+ kick_origin[0]=bb.getFloat();
+ kick_origin[1]=bb.getFloat();
+ kick_origin[2]=bb.getFloat();
+
+ v_dmg_roll=bb.getFloat();
+ v_dmg_pitch=bb.getFloat();
+ v_dmg_time=bb.getFloat();
+ fall_time=bb.getFloat();
+ fall_value=bb.getFloat();
+ damage_alpha=bb.getFloat();
+ bonus_alpha=bb.getFloat();
+
+ damage_blend[0]=bb.getFloat();
+ damage_blend[1]=bb.getFloat();
+ damage_blend[2]=bb.getFloat();
+
+ v_angle[0]=bb.getFloat();
+ v_angle[1]=bb.getFloat();
+ v_angle[2]=bb.getFloat();
+
+ bobtime=bb.getFloat();
+
+ oldviewangles[0]=bb.getFloat();
+ oldviewangles[1]=bb.getFloat();
+ oldviewangles[2]=bb.getFloat();
+
+ oldvelocity[0]=bb.getFloat();
+ oldvelocity[1]=bb.getFloat();
+ oldvelocity[2]=bb.getFloat();
+
+ next_drown_time=bb.getFloat();
+
+ old_waterlevel=bb.getInt();
+ breather_sound=bb.getInt();
+ machinegun_shots=bb.getInt();
+ anim_end=bb.getInt();
+ anim_priority=bb.getInt();
+ anim_duck=bb.getInt()!=0;
+ anim_run=bb.getInt()!=0;
+
+ quad_framenum=bb.getFloat();
+ invincible_framenum=bb.getFloat();
+ breather_framenum=bb.getFloat();
+ enviro_framenum=bb.getFloat();
+
+ grenade_blew_up= bb.getInt()!=0;
+ grenade_time=bb.getFloat();
+ silencer_shots=bb.getInt();
+ weapon_sound=bb.getInt();
+ pickup_msg_time=bb.getFloat();
+ flood_locktill=bb.getFloat();
+ flood_when [0]=bb.getFloat();
+ flood_when [1]=bb.getFloat();
+ flood_when [2]=bb.getFloat();
+ flood_when [3]=bb.getFloat();
+ flood_when [4]=bb.getFloat();
+ flood_when [5]=bb.getFloat();
+ flood_when [6]=bb.getFloat();
+ flood_when [7]=bb.getFloat();
+ flood_when [8]=bb.getFloat();
+ flood_when [9]=bb.getFloat();
+ flood_whenhead=bb.getInt();
+ respawn_time=bb.getFloat();
+ chase_target=GameUtil.g_edicts[bb.getInt()];
+ update_chase=bb.getInt()!=0;
+ }
+ public void dump() {
+
+ Com.Println("ping: " + ping);
+
+ pers.dump();
+ resp.dump();
+
+ old_pmove.dump();
+
+ Com.Println("showscores: " + showscores);
+ Com.Println("showinventury: " + showinventory);
+ Com.Println("showhelp: " + showhelp);
+ Com.Println("showhelpicon: " + showhelpicon);
+ Com.Println("ammoindex: " + ammo_index);
+
+ Com.Println("buttons: " + buttons);
+ Com.Println("oldbuttons: " + oldbuttons);
+ Com.Println("latchedbuttons: " + latched_buttons);
+
+ Com.Println("weaponthunk: " + weapon_thunk);
+
+ Com.Println("newweapon: " + newweapon);
+
+ Com.Println("damage_armor: " + damage_armor);
+ Com.Println("damage_parmor: " + damage_parmor);
+ Com.Println("damage_blood: " + damage_blood);
+ Com.Println("damage_knockback: " + damage_knockback);
+
+ Lib.printv("damage_from", damage_from);
+
+ Com.Println("killer_yaw: " + killer_yaw);
+
+ Com.Println("weaponstate: " + weaponstate);
+
+ Lib.printv("kick_angles", kick_angles);
+ Lib.printv("kick_origin", kick_origin);
+
+ Com.Println("v_dmg_roll: " + v_dmg_roll);
+ Com.Println("v_dmg_pitch: " + v_dmg_pitch);
+ Com.Println("v_dmg_time: " + v_dmg_time);
+
+ Com.Println("fall_time: " + fall_time);
+ Com.Println("fall_value: " + fall_value);
+ Com.Println("damage_alpha: " + damage_alpha);
+ Com.Println("bonus_alpha: " + bonus_alpha);
+
+ Lib.printv("damage_blend", damage_blend);
+
+ Lib.printv("v_angle", v_angle);
+
+ Com.Println("bobtime: " + bobtime);
+
+ Lib.printv("oldviewangles", oldviewangles);
+ Lib.printv("oldvelocity", oldvelocity);
+
+ Com.Println("next_downtime: " + next_drown_time);
+
+ Com.Println("old_waterlevel: " + old_waterlevel);
+ Com.Println("breathersound: " + breather_sound);
+ Com.Println("machinegun_shots: " + machinegun_shots);
+ Com.Println("anim_end: " + anim_end);
+ Com.Println("anim_priority: " + anim_priority);
+ Com.Println("anim_duck: " + anim_duck);
+ Com.Println("anim_run: " + anim_run);
+
+ Com.Println("quad_framenum: " + quad_framenum);
+ Com.Println("invincible_framenum: " + invincible_framenum);
+ Com.Println("breather_framenum: " + breather_framenum);
+ Com.Println("enviro_framenum: " + enviro_framenum);
+
+ Com.Println("grenade_blew_up: " + grenade_blew_up);
+ Com.Println("grenade_time: " + grenade_time);
+ Com.Println("silencer_shots: " + silencer_shots);
+ Com.Println("weapon_sound: " + weapon_sound);
+ Com.Println("pickup_msg_time: " + pickup_msg_time);
+ Com.Println("flood_locktill: " + flood_locktill);
+
+ Lib.printv("flood_when", flood_when);
+
+ Com.Println("flood_whenhead: " + flood_whenhead);
+ Com.Println("respawn_time: " + respawn_time);
+ Com.Println("chase_target: " + chase_target);
+ Com.Println("update_chase: " + update_chase);
+
+ }
+
+}
diff --git a/src/jake2/game/gitem_armor_t.java b/src/jake2/game/gitem_armor_t.java
new file mode 100644
index 0000000..91876f2
--- /dev/null
+++ b/src/jake2/game/gitem_armor_t.java
@@ -0,0 +1,46 @@
+/*
+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 07.11.2003 by RST.
+// $Id: gitem_armor_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+public class gitem_armor_t {
+
+ public gitem_armor_t(
+ int base_count,
+ int max_count,
+ float normal_protection,
+ float energy_protection,
+ int armor) {
+ this.base_count= base_count;
+ this.max_count= max_count;
+ this.normal_protection= normal_protection;
+ this.energy_protection= energy_protection;
+ this.armor= armor;
+ }
+
+ int base_count;
+ int max_count;
+ float normal_protection;
+ float energy_protection;
+ int armor;
+}
diff --git a/src/jake2/game/gitem_t.java b/src/jake2/game/gitem_t.java
new file mode 100644
index 0000000..2f28e1a
--- /dev/null
+++ b/src/jake2/game/gitem_t.java
@@ -0,0 +1,142 @@
+/*
+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 20.11.2003 by RST.
+// $Id: gitem_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.*;
+
+public class gitem_t
+{
+ public gitem_t(int xxx)
+ {
+ index = xxx;
+ }
+
+ public gitem_t(
+ String classname,
+ EntInteractAdapter pickup,
+ ItemUseAdapter use,
+ ItemDropAdapter drop,
+ EntThinkAdapter weaponthink)
+ {}
+
+
+ public gitem_t(
+ String classname,
+ EntInteractAdapter pickup,
+ ItemUseAdapter use,
+ ItemDropAdapter drop,
+ EntThinkAdapter weaponthink,
+ String pickup_sound,
+ String world_model,
+ int world_model_flags,
+ String view_model,
+ String icon,
+ String pickup_name,
+ int count_width,
+ int quantity,
+ String ammo,
+ int flags,
+ int weapmodel,
+ gitem_armor_t info,
+ int tag,
+ String precaches)
+ {
+ this.classname = classname;
+ this.pickup = pickup;
+ this.use = use;
+ this.drop = drop;
+ this.weaponthink = weaponthink;
+ this.pickup_sound = pickup_sound;
+ this.world_model = world_model;
+ this.world_model_flags = world_model_flags;
+ this.view_model = view_model;
+ this.icon = icon;
+ this.pickup_name = pickup_name;
+ this.count_width = count_width;
+ this.quantity = quantity;
+ this.ammo = ammo;
+ this.flags = flags;
+ this.weapmodel = weapmodel;
+ this.info = info;
+ this.tag = tag;
+ this.precaches = precaches;
+ }
+
+ String classname; // spawning name
+ EntInteractAdapter pickup;
+ ItemUseAdapter use;
+ ItemDropAdapter drop;
+ EntThinkAdapter weaponthink;
+
+ String pickup_sound;
+ String world_model;
+
+ int world_model_flags;
+
+ String view_model;
+
+ // client side info
+ String icon;
+ String pickup_name; // for printing on pickup
+ int count_width; // number of digits to display by icon
+
+ int quantity; // for ammo how much, for weapons how much is used per shot
+ String ammo; // for weapons
+ int flags; // IT_* flags
+
+ int weapmodel; // weapon model index (for weapons)
+
+ Object info;
+ int tag;
+
+ String precaches; // string of all models, sounds, and images this item will use
+
+
+ public static void main(String args[])
+ {
+ gitem_t xxx = new gitem_t(123);
+ gitem_t i2 =
+ new gitem_t(
+ "item_armor_combat",
+ GameAI.Pickup_Armor,
+ null,
+ null,
+ null,
+ "misc/ar1_pkup.wav",
+ "models/items/armor/combat/tris.md2",
+ Defines.EF_ROTATE,
+ null,
+ /* icon */
+ "i_combatarmor",
+ /* pickup */
+ "Combat Armor",
+ /* width */
+ 3, 0, null, Defines.IT_ARMOR, 0, GameAI.combatarmor_info, Defines.ARMOR_COMBAT,
+ /* precache */
+ "");
+ }
+
+ int index;
+}
diff --git a/src/jake2/game/level_locals_t.java b/src/jake2/game/level_locals_t.java
new file mode 100644
index 0000000..18038bf
--- /dev/null
+++ b/src/jake2/game/level_locals_t.java
@@ -0,0 +1,69 @@
+/*
+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 20.11.2003 by RST
+// $Id: level_locals_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+
+package jake2.game;
+
+public class level_locals_t {
+ //
+ // this structure is cleared as each map is entered
+ // it is read/written to the level.sav file for savegames
+ //
+ public int framenum;
+ public float time;
+
+ public String level_name= ""; // the descriptive name (Outer Base, etc)
+ public String mapname= ""; // the server name (base1, etc)
+ public String nextmap= ""; // go here when fraglimit is hit
+
+ // intermission state
+ public float intermissiontime; // time the intermission was started
+ public String changemap;
+ public boolean exitintermission;
+ public float[] intermission_origin= { 0, 0, 0 };
+ public float[] intermission_angle= { 0, 0, 0 };
+
+ public edict_t sight_client; // changed once each frame for coop games
+
+ public edict_t sight_entity;
+ public int sight_entity_framenum;
+ public edict_t sound_entity;
+ public int sound_entity_framenum;
+ public edict_t sound2_entity;
+ public int sound2_entity_framenum;
+
+ public int pic_health;
+
+ public int total_secrets;
+ public int found_secrets;
+
+ public int total_goals;
+ public int found_goals;
+
+ public int total_monsters;
+ public int killed_monsters;
+
+ public edict_t current_entity; // entity running from G_RunFrame
+ public int body_que; // dead bodies
+
+ public int power_cubes; // ugly necessity for coop
+}
diff --git a/src/jake2/game/link_t.java b/src/jake2/game/link_t.java
new file mode 100644
index 0000000..744cb09
--- /dev/null
+++ b/src/jake2/game/link_t.java
@@ -0,0 +1,33 @@
+/*
+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 31.10.2003 by RST
+// $Id: link_t.java,v 1.1 2004-07-07 19:59:25 hzi Exp $
+// simple linked structure often used in quake.
+
+package jake2.game;
+
+public class link_t {
+ public link_t(Object o) {
+ this.o = o;
+ }
+ public link_t prev, next;
+ public Object o;
+}
diff --git a/src/jake2/game/mapsurface_t.java b/src/jake2/game/mapsurface_t.java
new file mode 100644
index 0000000..c053da0
--- /dev/null
+++ b/src/jake2/game/mapsurface_t.java
@@ -0,0 +1,37 @@
+/*
+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 02.01.2004 by RST.
+// $Id: mapsurface_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+
+// import jake2.*;
+// import jake2.client.*;
+// import jake2.game.*;
+// import jake2.qcommon.*;
+// import jake2.render.*;
+// import jake2.server.*;
+
+public class mapsurface_t {
+ public csurface_t c = new csurface_t();
+ public String rname;
+}
diff --git a/src/jake2/game/mframe_t.java b/src/jake2/game/mframe_t.java
new file mode 100644
index 0000000..6e81af4
--- /dev/null
+++ b/src/jake2/game/mframe_t.java
@@ -0,0 +1,36 @@
+/*
+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 11.11.2003 by RST.
+// $Id: mframe_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+public class mframe_t {
+ public mframe_t(AIAdapter ai, float dist, EntThinkAdapter think) {
+ this.ai= ai;
+ this.dist= dist;
+ this.think= think;
+ }
+
+ public AIAdapter ai;
+ public float dist;
+ public EntThinkAdapter think;
+}
diff --git a/src/jake2/game/mmove_t.java b/src/jake2/game/mmove_t.java
new file mode 100644
index 0000000..b0c19d0
--- /dev/null
+++ b/src/jake2/game/mmove_t.java
@@ -0,0 +1,38 @@
+/*
+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 11.11.2003 by RST.
+// $Id: mmove_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+public class mmove_t {
+ public mmove_t(int firstframe, int lastframe, mframe_t frame[], EntThinkAdapter endfunc) {
+ this.firstframe= firstframe;
+ this.lastframe= lastframe;
+ this.frame= frame;
+ this.endfunc= endfunc;
+ }
+
+ public int firstframe;
+ public int lastframe;
+ public mframe_t frame[]; //ptr
+ public EntThinkAdapter endfunc;
+}
diff --git a/src/jake2/game/monsterinfo_t.java b/src/jake2/game/monsterinfo_t.java
new file mode 100644
index 0000000..48b96f0
--- /dev/null
+++ b/src/jake2/game/monsterinfo_t.java
@@ -0,0 +1,63 @@
+/*
+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 31.10.2003 by RST.
+// $Id: monsterinfo_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+public class monsterinfo_t {
+
+ public mmove_t currentmove;
+ public int aiflags;
+ public int nextframe;
+ public float scale;
+
+ public EntThinkAdapter stand;
+ public EntThinkAdapter idle;
+ public EntThinkAdapter search;
+ public EntThinkAdapter walk;
+ public EntThinkAdapter run;
+
+ public EntDodgeAdapter dodge;
+
+ public EntThinkAdapter attack;
+ public EntThinkAdapter melee;
+
+ public EntInteractAdapter sight;
+
+ public EntThinkAdapter checkattack;
+
+ public float pausetime;
+ public float attack_finished;
+
+ public float[] saved_goal= { 0, 0, 0 };
+ public float search_time;
+ public float trail_time;
+ public float[] last_sighting= { 0, 0, 0 };
+ public int attack_state;
+ public int lefty;
+ public float idle_time;
+ public int linkcount;
+
+ public int power_armor_type;
+ public int power_armor_power;
+
+}
diff --git a/src/jake2/game/moveinfo_t.java b/src/jake2/game/moveinfo_t.java
new file mode 100644
index 0000000..16b0b50
--- /dev/null
+++ b/src/jake2/game/moveinfo_t.java
@@ -0,0 +1,54 @@
+/*
+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 31.10.2003 by RST.
+// $Id: moveinfo_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+public class moveinfo_t {
+ // fixed data
+ float[] start_origin= { 0, 0, 0 };
+ float[] start_angles= { 0, 0, 0 };
+ float[] end_origin= { 0, 0, 0 };
+ float[] end_angles= { 0, 0, 0 };
+
+ int sound_start;
+ int sound_middle;
+ int sound_end;
+
+ float accel;
+ float speed;
+ float decel;
+ float distance;
+
+ float wait;
+
+ // state data
+ int state;
+ float[] dir= { 0, 0, 0 };
+
+ float current_speed;
+ float move_speed;
+ float next_speed;
+ float remaining_distance;
+ float decel_distance;
+ EntThinkAdapter endfunc;
+}
diff --git a/src/jake2/game/player_state_t.java b/src/jake2/game/player_state_t.java
new file mode 100644
index 0000000..f8d4860
--- /dev/null
+++ b/src/jake2/game/player_state_t.java
@@ -0,0 +1,165 @@
+/*
+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 31.10.2003 by RST.
+// $Id: player_state_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import jake2.*;
+import jake2.*;
+import jake2.qcommon.Com;
+import jake2.util.Lib;
+import jake2.util.Math3D;
+
+public class player_state_t {
+ // player_state_t is the information needed in addition to pmove_state_t
+ // to rendered a view. There will only be 10 player_state_t sent each second,
+ // but the number of pmove_state_t changes will be reletive to client
+ // frame rates
+
+ public pmove_state_t pmove = new pmove_state_t(); // for prediction
+
+ // these fields do not need to be communicated bit-precise
+ public float[] viewangles = { 0, 0, 0 }; // for fixed views
+ public float[] viewoffset = { 0, 0, 0 }; // add to pmovestate->origin
+ public float[] kick_angles = { 0, 0, 0 }; // add to view direction to get render angles
+
+ // set by weapon kicks, pain effects, etc
+ public float[] gunangles = { 0, 0, 0 };
+ public float[] gunoffset = { 0, 0, 0 };
+ public int gunindex;
+ public int gunframe;
+
+ public float blend[] = new float[4]; // rgba full screen effect
+
+ public float fov; // horizontal field of view
+
+ public int rdflags; // refdef flags
+
+ public short stats[] = new short[Defines.MAX_STATS];
+
+ /**
+ *
+ */
+ // TODO bugfix cwei
+ private static player_state_t prototype = new player_state_t();
+
+ public void clear() {
+ this.set(prototype);
+ }
+
+ public player_state_t getClone()
+ {
+ return new player_state_t().set(this);
+ }
+
+ public player_state_t set(player_state_t from)
+ {
+ pmove.set(from.pmove);
+ Math3D.VectorCopy(from.viewangles, viewangles);
+ Math3D.VectorCopy(from.viewoffset,viewoffset);
+ Math3D.VectorCopy(from.kick_angles, kick_angles);
+
+ Math3D.VectorCopy(from.gunangles,gunangles);
+ Math3D.VectorCopy(from.gunoffset, gunoffset);
+
+ gunindex = from.gunindex;
+ gunframe = from.gunframe;
+
+ blend[0] = from.blend[0];
+ blend[1] = from.blend[1];
+ blend[2] = from.blend[2];
+ blend[3] = from.blend[3];
+
+ fov = from.fov;
+ rdflags = from.rdflags;
+
+ stats = new short[Defines.MAX_STATS];
+ System.arraycopy(from.stats, 0, stats,0, Defines.MAX_STATS);
+
+ return this;
+ }
+
+ public void load(ByteBuffer bb) throws IOException {
+ pmove.load(bb);
+
+ viewangles[0] = bb.getFloat();
+ viewangles[1] = bb.getFloat();
+ viewangles[2] = bb.getFloat();
+
+ viewoffset[0] = bb.getFloat();
+ viewoffset[1] = bb.getFloat();
+ viewoffset[2] = bb.getFloat();
+
+ kick_angles[0] = bb.getFloat();
+ kick_angles[1] = bb.getFloat();
+ kick_angles[2] = bb.getFloat();
+
+ gunangles[0] = bb.getFloat();
+ gunangles[1] = bb.getFloat();
+ gunangles[2] = bb.getFloat();
+
+ gunoffset[0] = bb.getFloat();
+ gunoffset[1] = bb.getFloat();
+ gunoffset[2] = bb.getFloat();
+
+ gunindex = bb.getInt();
+ gunframe = bb.getInt();
+
+ blend[0] = bb.getFloat();
+ blend[1] = bb.getFloat();
+ blend[2] = bb.getFloat();
+ blend[3] = bb.getFloat();
+
+ fov = bb.getFloat();
+
+ rdflags = bb.getInt();
+
+ for (int n = 0; n < Defines.MAX_STATS; n++)
+ stats[n] = bb.getShort();
+
+ }
+
+ public void dump() {
+ pmove.dump();
+
+ Lib.printv("viewangles", viewangles);
+ Lib.printv("viewoffset", viewoffset);
+ Lib.printv("kick_angles", kick_angles);
+ Lib.printv("gunangles", gunangles);
+ Lib.printv("gunoffset", gunoffset);
+
+ Com.Println("gunindex: " + gunindex);
+ Com.Println("gunframe: " + gunframe);
+
+ Lib.printv("blend", blend);
+
+ Com.Println("fov: " + fov);
+
+ Com.Println("rdflags: " + rdflags);
+
+ for (int n = 0; n < Defines.MAX_STATS; n++)
+ System.out.println("stats[" + n + "]: " + stats[n]);
+ }
+}
diff --git a/src/jake2/game/pmove_state_t.java b/src/jake2/game/pmove_state_t.java
new file mode 100644
index 0000000..6c0906e
--- /dev/null
+++ b/src/jake2/game/pmove_state_t.java
@@ -0,0 +1,130 @@
+/*
+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 31.10.2003 by RST.
+// $Id: pmove_state_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+package jake2.game;
+
+import jake2.qcommon.Com;
+import jake2.util.Math3D;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class pmove_state_t {
+ // this structure needs to be communicated bit-accurate
+ // from the server to the client to guarantee that
+ // prediction stays in sync, so no floats are used.
+ // if any part of the game code modifies this struct, it
+ // will result in a prediction error of some degree.
+
+ public int pm_type;
+
+ public short origin[] = { 0, 0, 0 }; // 12.3
+ public short velocity[] = { 0, 0, 0 }; // 12.3
+ public byte pm_flags; // ducked, jump_held, etc
+ public byte pm_time; // each unit = 8 ms
+ public short gravity;
+ public short delta_angles[] = { 0, 0, 0 }; // add to command angles to get view direction
+ // changed by spawns, rotating objects, and teleporters
+
+ private static pmove_state_t prototype = new pmove_state_t();
+
+ public void reset()
+ {
+ this.set(prototype);
+ }
+
+ public void set(pmove_state_t from) {
+ pm_type = from.pm_type;
+ Math3D.VectorCopy(from.origin, origin);
+ Math3D.VectorCopy(from.velocity, velocity);
+ pm_flags = from.pm_flags;
+ pm_time = from.pm_time;
+ gravity = from.gravity;
+ Math3D.VectorCopy(from.delta_angles, delta_angles);
+ }
+
+ public boolean equals(pmove_state_t p2) {
+ if (pm_type == p2.pm_type
+ && origin[0] == p2.origin[0]
+ && origin[1] == p2.origin[1]
+ && origin[2] == p2.origin[2]
+ && velocity[0] == p2.velocity[0]
+ && velocity[1] == p2.velocity[1]
+ && velocity[2] == p2.origin[2]
+ && pm_flags == p2.pm_flags
+ && pm_time == p2.pm_time
+ && gravity == gravity
+ && delta_angles[0] == p2.delta_angles[0]
+ && delta_angles[1] == p2.delta_angles[1]
+ && delta_angles[2] == p2.origin[2])
+ return true;
+
+ return false;
+ }
+
+ public void load(ByteBuffer bb) throws IOException {
+
+ pm_type = bb.getInt();
+
+ origin[0] = bb.getShort();
+ origin[1] = bb.getShort();
+ origin[2] = bb.getShort();
+
+ velocity[0] = bb.getShort();
+ velocity[1] = bb.getShort();
+ velocity[2] = bb.getShort();
+
+ pm_flags = bb.get();
+ pm_time = bb.get();
+ gravity = bb.getShort();
+
+ bb.getShort();
+
+ delta_angles[0] = bb.getShort();
+ delta_angles[1] = bb.getShort();
+ delta_angles[2] = bb.getShort();
+
+ }
+
+ public void dump() {
+ Com.Println("pm_type: " + pm_type);
+
+ Com.Println("origin[0]: " + origin[0]);
+ Com.Println("origin[1]: " + origin[0]);
+ Com.Println("origin[2]: " + origin[0]);
+
+ Com.Println("velocity[0]: " + velocity[0]);
+ Com.Println("velocity[1]: " + velocity[1]);
+ Com.Println("velocity[2]: " + velocity[2]);
+
+ Com.Println("pmflags: " + pm_flags);
+ Com.Println("pmtime: " + pm_time);
+ Com.Println("gravity: " + gravity);
+
+ Com.Println("delta-angle[0]: " + delta_angles[0]);
+ Com.Println("delta-angle[1]: " + delta_angles[0]);
+ Com.Println("delta-angle[2]: " + delta_angles[0]);
+ }
+
+
+
+} \ No newline at end of file
diff --git a/src/jake2/game/pmove_t.java b/src/jake2/game/pmove_t.java
new file mode 100644
index 0000000..d4138f4
--- /dev/null
+++ b/src/jake2/game/pmove_t.java
@@ -0,0 +1,83 @@
+/*
+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 31.10.2003 by RST.
+// $Id: pmove_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+import jake2.*;
+import jake2.server.SV_WORLD;
+
+public class pmove_t {
+
+ public static class TraceAdapter {
+ // callbacks to test the world
+ public trace_t trace(float[] start, float[] mins, float[] maxs, float[] end) {
+ return null;
+ }
+ }
+
+ public static class PointContentsAdapter {
+ // callbacks to test the world
+ public int pointcontents(float[] point) {
+ return 0;
+ }
+ }
+
+ // state (in / out)
+ public pmove_state_t s = new pmove_state_t();
+
+ // command (in)
+ public usercmd_t cmd = new usercmd_t();
+ public boolean snapinitial; // if s has been changed outside pmove
+
+ // results (out)
+ public int numtouch;
+ public edict_t touchents[] = new edict_t[Defines.MAXTOUCH];
+
+ public float[] viewangles = { 0, 0, 0 }; // clamped
+ public float viewheight;
+
+ public float[] mins = { 0, 0, 0 }, maxs = { 0, 0, 0 }; // bounding box size
+
+ public edict_t groundentity;
+ public int watertype;
+ public int waterlevel;
+
+ public TraceAdapter trace;
+ public PointContentsAdapter pointcontents;
+
+ public void clear() {
+ groundentity = null;
+ waterlevel = watertype =0;
+ trace = null;
+ pointcontents = null;
+ mins = new float [3];
+ maxs = new float [3];
+ viewheight=0;
+ viewangles = new float [3];
+ touchents = new edict_t[Defines.MAXTOUCH];
+ numtouch =0;
+ snapinitial=false;
+ cmd = new usercmd_t();
+ s = new pmove_state_t();
+ }
+}
diff --git a/src/jake2/game/pushed_t.java b/src/jake2/game/pushed_t.java
new file mode 100644
index 0000000..04958f9
--- /dev/null
+++ b/src/jake2/game/pushed_t.java
@@ -0,0 +1,31 @@
+/*
+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 31.10.2003 by RST.
+// $Id: pushed_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+public class pushed_t {
+ public edict_t ent;
+ public float[] origin= { 0.0f, 0.0f, 0.0f };
+ public float[] angles= { 0.0f, 0.0f, 0.0f };
+ public float deltayaw;
+}
diff --git a/src/jake2/game/spawn_t.java b/src/jake2/game/spawn_t.java
new file mode 100644
index 0000000..b485bf7
--- /dev/null
+++ b/src/jake2/game/spawn_t.java
@@ -0,0 +1,34 @@
+/*
+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 19.11.2003 by RST.
+// $Id: spawn_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+public class spawn_t {
+ public spawn_t(String name, EntThinkAdapter spawn) {
+ this.name = name;
+ this.spawn = spawn;
+ }
+
+ String name;
+ EntThinkAdapter spawn;
+}
diff --git a/src/jake2/game/spawn_temp_t.java b/src/jake2/game/spawn_temp_t.java
new file mode 100644
index 0000000..8b8113b
--- /dev/null
+++ b/src/jake2/game/spawn_temp_t.java
@@ -0,0 +1,129 @@
+/*
+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 31.10.2003 by RST.
+// $Id: spawn_temp_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.*;
+
+public class spawn_temp_t {
+ // world vars
+ public String sky="";
+ public float skyrotate;
+ public float[] skyaxis = { 0, 0, 0 };
+
+ public String nextmap="";
+
+ public int lip;
+ public int distance;
+ public int height;
+
+ public String noise="";
+ public float pausetime;
+
+ public String item="";
+ public String gravity="";
+
+ public float minyaw;
+ public float maxyaw;
+ public float minpitch;
+ public float maxpitch;
+
+ public boolean set(String key, String value) {
+ if (key.equals("lip")) {
+ lip=Lib.atoi(value);
+ return true;
+ } // F_INT, FFL_SPAWNTEMP),
+
+ if (key.equals("distance")) {
+ distance=Lib.atoi(value);
+ return true;
+ } // F_INT, FFL_SPAWNTEMP),
+
+ if (key.equals("height")) {
+ height=Lib.atoi(value);
+ return true;
+ } // F_INT, FFL_SPAWNTEMP),
+
+ if (key.equals("noise")) {
+ noise = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING, FFL_SPAWNTEMP),
+
+ if (key.equals("pausetime")) {
+ pausetime = Lib.atof(value);
+ return true;
+ } // F_FLOAT, FFL_SPAWNTEMP),
+
+ if (key.equals("item")) {
+ item = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING, FFL_SPAWNTEMP),
+
+ if (key.equals("gravity")) {
+ gravity = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING, FFL_SPAWNTEMP),
+
+ if (key.equals("sky")) {
+ sky = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING, FFL_SPAWNTEMP),
+
+ if (key.equals("skyrotate")) {
+ skyrotate=Lib.atof(value);
+ return true;
+ } // F_FLOAT, FFL_SPAWNTEMP),
+
+ if (key.equals("skyaxis")) {
+ skyaxis=Lib.atov(value);
+ return true;
+ } // F_VECTOR, FFL_SPAWNTEMP),
+
+ if (key.equals("minyaw")) {
+ minyaw=Lib.atof(value);
+ return true;
+ } // F_FLOAT, FFL_SPAWNTEMP),
+
+ if (key.equals("maxyaw")) {
+ maxyaw=Lib.atof(value);
+ return true;
+ } // F_FLOAT, FFL_SPAWNTEMP),
+
+ if (key.equals("minpitch")) {
+ minpitch = Lib.atof(value);
+ return true;
+ } // F_FLOAT, FFL_SPAWNTEMP),
+
+ if (key.equals("maxpitch")) {
+ maxpitch = Lib.atof(value);
+ return true;
+ } // F_FLOAT, FFL_SPAWNTEMP),
+
+ if (key.equals("nextmap")) {
+ nextmap = GameSpawn.ED_NewString(value);
+ return true;
+ } // F_LSTRING, FFL_SPAWNTEMP),
+
+ return false;
+ }
+}
diff --git a/src/jake2/game/trace_t.java b/src/jake2/game/trace_t.java
new file mode 100644
index 0000000..5c97aa5
--- /dev/null
+++ b/src/jake2/game/trace_t.java
@@ -0,0 +1,54 @@
+/*
+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 31.10.2003 by RST.
+// $Id: trace_t.java,v 1.1 2004-07-07 19:59:26 hzi Exp $
+
+package jake2.game;
+
+import jake2.util.Lib;
+
+//a trace is returned when a box is swept through the world
+public class trace_t implements Cloneable {
+ public boolean allsolid; // if true, plane is not valid
+ public boolean startsolid; // if true, the initial point was in a solid area
+ public float fraction; // time completed, 1.0 = didn't hit anything
+ public float[] endpos = { 0, 0, 0 }; // final position
+ // memory
+ public cplane_t plane = new cplane_t(); // surface normal at impact
+ // pointer
+ public csurface_t surface; // surface hit
+ public int contents; // contents on other side of surface hit
+ // pointer
+ public edict_t ent; // not set by CM_*() functions
+
+ // =============
+ public trace_t getClone() {
+ trace_t out = null;
+ try {
+ out = (trace_t) this.clone();
+ out.plane = plane.getClone();
+ endpos = Lib.clone(endpos);
+ }
+ catch (CloneNotSupportedException e) {
+ }
+ return out;
+ }
+}
diff --git a/src/jake2/game/usercmd_t.java b/src/jake2/game/usercmd_t.java
new file mode 100644
index 0000000..f28c7cf
--- /dev/null
+++ b/src/jake2/game/usercmd_t.java
@@ -0,0 +1,86 @@
+/*
+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 31.10.2003 by RST.
+// $Id: usercmd_t.java,v 1.1 2004-07-07 19:59:27 hzi Exp $
+
+package jake2.game;
+
+import java.util.Arrays;
+
+import jake2.util.Lib;
+
+public class usercmd_t implements Cloneable {
+ public byte msec;
+ public byte buttons;
+ public short angles[] = new short[3];
+ public short forwardmove, sidemove, upmove;
+ public byte impulse; // remove?
+ public byte lightlevel; // light level the player is standing on
+
+ public void reset() {
+ forwardmove = sidemove = upmove = msec = buttons = impulse = lightlevel = 0;
+ Arrays.fill(angles, (short)0);
+ }
+
+ public usercmd_t() {};
+
+ public usercmd_t(usercmd_t from) {
+ msec = from.msec;
+ buttons = from.buttons;
+ angles[0] = from.angles[0];
+ angles[1] = from.angles[1];
+ angles[2] = from.angles[2];
+ forwardmove = from.forwardmove;
+ sidemove = from.sidemove;
+ upmove = from.upmove;
+ impulse = from.impulse;
+ lightlevel = from.lightlevel;
+ }
+
+ public usercmd_t set(usercmd_t from)
+ {
+ msec = from.msec;
+ buttons = from.buttons;
+ angles[0] = from.angles[0];
+ angles[1] = from.angles[1];
+ angles[2] = from.angles[2];
+ forwardmove = from.forwardmove;
+ sidemove = from.sidemove;
+ upmove = from.upmove;
+ impulse = from.impulse;
+ lightlevel = from.lightlevel;
+
+ return this;
+ }
+
+ public usercmd_t getClone()
+ {
+ try {
+ usercmd_t u1 = (usercmd_t) this.clone();
+ u1.angles = Lib.clone(angles);
+ return u1;
+ }
+ catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+} \ No newline at end of file